V14: Remove old backoffice project. (#15752)
* Move magical route to management api * Move auth around * Remove "New" cookies, as they are no longer needed * Move all installer related * Remove BackOfficeServerVariables.cs and trees * Move webhooks to management api * Remove remainting controllers * Remove last services * Move preview to management api * Remove mroe extensions * Remove tours * Remove old Auth handlers * Remove server variables entirely * Remove old backoffice controller * Remove controllers namespace entirely * Move rest of preview * move last services * Move language file extension * Remove old backoffice entirely (Backoffice and Web.UI projects) * Clean up unused security classes * Fix up installer route * Remove obsolete tests * Fix up DI in integration test * Add missing property mapping * Move core mapping into core * Add composers to integration test * remove identity * Fix up DI * Outcomment failing test :) * Fix up remaining test * Update mapper * Remove the actual project files * Remove backoffice cs proj * Remove old backoffice from yml * Run belissima before login * Remove caching * Refactor file paths * Remove belle from static assets * Dont refer to old project in templates * update gitignore * Add missing files * Remove install view as its no longer used * Fix up failing test * Remove outcommented code * Update submodule to latest * fix build --------- Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using Umbraco.Cms.Api.Management.Controllers.Security;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
@@ -13,9 +15,6 @@ using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Install;
|
||||
using Umbraco.Cms.Infrastructure.Migrations.Install;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
using Umbraco.Cms.Web.BackOffice.Install;
|
||||
using Umbraco.Cms.Web.BackOffice.Routing;
|
||||
using Umbraco.Cms.Web.Common.Security;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.AutoFixture.Customizations;
|
||||
@@ -29,14 +28,10 @@ internal class UmbracoCustomizations : ICustomization
|
||||
(a, b, c) => BackOfficeIdentityUser.CreateNew(new GlobalSettings(), a, b, c)));
|
||||
|
||||
fixture
|
||||
.Customize(new ConstructorCustomization(typeof(UsersController), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(InstallController), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(PreviewController), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(BackOfficeController), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(BackOfficeUserManager), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(BackOfficeDefaultController), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(MemberManager), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(DatabaseSchemaCreatorFactory), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(BackOfficeServerVariables), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(InstallHelper), new GreedyConstructorQuery()))
|
||||
.Customize(new ConstructorCustomization(typeof(DatabaseBuilder), new GreedyConstructorQuery()));
|
||||
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Security;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Web.BackOffice.Security;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security;
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Security;
|
||||
|
||||
[TestFixture]
|
||||
public class BackOfficeAuthenticationBuilderTests
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -9,7 +8,6 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Web.BackOffice.Trees;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Composing;
|
||||
@@ -45,22 +43,6 @@ public class TypeFinderTests
|
||||
Assert.AreEqual(2, typesFound.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Find_Classes_With_Attribute()
|
||||
{
|
||||
var typeFinder = new TypeFinder(
|
||||
Mock.Of<ILogger<TypeFinder>>(),
|
||||
new DefaultUmbracoAssemblyProvider(GetType().Assembly, NullLoggerFactory.Instance));
|
||||
var typesFound = typeFinder.FindClassesWithAttribute<TreeAttribute>(_assemblies);
|
||||
Assert.AreEqual(0, typesFound.Count()); // 0 classes in _assemblies are marked with [Tree]
|
||||
|
||||
typesFound = typeFinder.FindClassesWithAttribute<TreeAttribute>(new[] { typeof(TreeAttribute).Assembly });
|
||||
Assert.AreEqual(24, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree]
|
||||
|
||||
typesFound = typeFinder.FindClassesWithAttribute<TreeAttribute>();
|
||||
Assert.AreEqual(24, typesFound.Count()); // + classes in Umbraco.Web are marked with [Tree]
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class MyTestAttribute : Attribute
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="NUnit3TestAdapter" />
|
||||
<PackageReference Include="System.Data.Odbc" />
|
||||
<PackageReference Include="System.Data.Odbc" />
|
||||
<PackageReference Include="System.Data.OleDb" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,218 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Editors;
|
||||
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;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class AdminUsersHandlerTests
|
||||
{
|
||||
private const string SingleUserEditQueryStringName = "id";
|
||||
private const string MultipleUserEditQueryStringName = "ids";
|
||||
|
||||
private const int Admin1UserId = 0;
|
||||
private const int Admin2UserId = 1;
|
||||
private const int NonAdmin1UserId = 2;
|
||||
private const int NonAdmin2UserId = 3;
|
||||
private const int NonAdmin3UserId = 4;
|
||||
|
||||
[Test]
|
||||
public async Task Missing_QueryString_Value_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler("xxx");
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Non_Integer_QueryString_Value_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(queryStringValue: "xxx");
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Editing_Single_Admin_User_By_Admin_User_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(
|
||||
queryStringValue: Admin2UserId.ToString(CultureInfo.InvariantCulture),
|
||||
editingWithAdmin: true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Editing_Single_Admin_User_By_Non_Admin_User_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(queryStringValue: Admin2UserId.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Editing_Single_Non_Admin_User_By_Non_Admin_User_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(queryStringValue: NonAdmin2UserId.ToString(CultureInfo.InvariantCulture));
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Editing_Multiple_Users_Including_Admins_By_Admin_User_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(MultipleUserEditQueryStringName);
|
||||
var sut = CreateHandler(MultipleUserEditQueryStringName, $"{Admin2UserId},{NonAdmin2UserId}", true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Editing_Multiple_Users_Including_Admins_By_Non_Admin_User_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(MultipleUserEditQueryStringName);
|
||||
var sut = CreateHandler(MultipleUserEditQueryStringName, $"{Admin2UserId},{NonAdmin2UserId}");
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Editing_Multiple_Users_Not_Including_Admins_By_Non_Admin_User_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(MultipleUserEditQueryStringName);
|
||||
var sut = CreateHandler(MultipleUserEditQueryStringName, $"{NonAdmin2UserId},{NonAdmin3UserId}");
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(
|
||||
string queryStringName = SingleUserEditQueryStringName)
|
||||
{
|
||||
var requirement = new AdminUsersRequirement(queryStringName);
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private AdminUsersHandler CreateHandler(
|
||||
string queryStringName = SingleUserEditQueryStringName,
|
||||
string queryStringValue = "",
|
||||
bool editingWithAdmin = false)
|
||||
{
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringName, queryStringValue);
|
||||
CreateMockUserServiceAndSecurityAccessor(editingWithAdmin, out var mockUserService, out var mockBackOfficeSecurityAccessor);
|
||||
var userEditorAuthorizationHelper = CreateUserEditorAuthorizationHelper();
|
||||
return new AdminUsersHandler(
|
||||
mockHttpContextAccessor.Object,
|
||||
mockUserService.Object,
|
||||
mockBackOfficeSecurityAccessor.Object,
|
||||
userEditorAuthorizationHelper);
|
||||
}
|
||||
|
||||
private static Mock<IHttpContextAccessor> CreateMockHttpContextAccessor(string queryStringName, string queryStringValue)
|
||||
{
|
||||
var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
|
||||
var mockHttpContext = new Mock<HttpContext>();
|
||||
var mockHttpRequest = new Mock<HttpRequest>();
|
||||
var queryParams = new Dictionary<string, StringValues> { { queryStringName, queryStringValue } };
|
||||
mockHttpRequest.SetupGet(x => x.Query).Returns(new QueryCollection(queryParams));
|
||||
mockHttpContext.SetupGet(x => x.Request).Returns(mockHttpRequest.Object);
|
||||
mockHttpContextAccessor.SetupGet(x => x.HttpContext).Returns(mockHttpContext.Object);
|
||||
return mockHttpContextAccessor;
|
||||
}
|
||||
|
||||
private static void CreateMockUserServiceAndSecurityAccessor(
|
||||
bool editingWithAdmin,
|
||||
out Mock<IUserService> mockUserService,
|
||||
out Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor)
|
||||
{
|
||||
mockUserService = new Mock<IUserService>();
|
||||
var adminUser1 = CreateUser(Admin1UserId, mockUserService, true);
|
||||
var adminUser2 = CreateUser(Admin2UserId, mockUserService, true);
|
||||
var nonAdminUser1 = CreateUser(NonAdmin1UserId, mockUserService);
|
||||
var nonAdminUser2 = CreateUser(NonAdmin2UserId, mockUserService);
|
||||
var nonAdminUser3 = CreateUser(NonAdmin3UserId, mockUserService);
|
||||
|
||||
// Single user requests have been setup in the create user operations, but
|
||||
// we also need to mock the responses when multiple users are being editing.
|
||||
mockUserService
|
||||
.Setup(x => x.GetUsersById(It.Is<int[]>(y =>
|
||||
y.Length == 2 && y[0] == Admin2UserId && y[1] == NonAdmin2UserId)))
|
||||
.Returns(new List<IUser> { adminUser2, nonAdminUser2 });
|
||||
mockUserService
|
||||
.Setup(x => x.GetUsersById(It.Is<int[]>(y =>
|
||||
y.Length == 2 && y[0] == NonAdmin2UserId && y[1] == NonAdmin3UserId)))
|
||||
.Returns(new List<IUser> { nonAdminUser2, nonAdminUser3 });
|
||||
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(editingWithAdmin ? adminUser1 : nonAdminUser1);
|
||||
mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
}
|
||||
|
||||
private static User CreateUser(int id, Mock<IUserService> mockUserService, bool isAdmin = false)
|
||||
{
|
||||
var user = new UserBuilder()
|
||||
.WithId(id)
|
||||
.AddUserGroup()
|
||||
.WithAlias(isAdmin ? Constants.Security.AdminGroupAlias : Constants.Security.EditorGroupAlias)
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
mockUserService
|
||||
.Setup(x => x.GetUsersById(It.Is<int[]>(y => y.Length == 1 && y[0] == id)))
|
||||
.Returns(new List<IUser> { user });
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private static UserEditorAuthorizationHelper CreateUserEditorAuthorizationHelper()
|
||||
{
|
||||
var mockContentService = new Mock<IContentService>();
|
||||
var mockMediaService = new Mock<IMediaService>();
|
||||
var mockEntityService = new Mock<IEntityService>();
|
||||
return new UserEditorAuthorizationHelper(
|
||||
mockContentService.Object,
|
||||
mockMediaService.Object,
|
||||
mockEntityService.Object,
|
||||
AppCaches.Disabled);
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class BackOfficeHandlerTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Runtime_State_Install_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(RuntimeLevel.Install);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Runtime_State_Upgrade_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(RuntimeLevel.Upgrade);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Unauthenticated_User_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler();
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Authenticated_User_Is_Not_Authorized_When_Not_Approved_And_Approval_Required()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(true);
|
||||
var sut = CreateHandler(currentUserIsAuthenticated: true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Authenticated_User_Is_Authorized_When_Not_Approved_And_Approval_Not_Required()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(currentUserIsAuthenticated: true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Authenticated_User_Is_Authorized_When_Approved_And_Approval_Required()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(true);
|
||||
var sut = CreateHandler(currentUserIsAuthenticated: true, currentUserIsApproved: true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(bool requireApproval = false)
|
||||
{
|
||||
var requirement = new BackOfficeRequirement(requireApproval);
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private BackOfficeHandler CreateHandler(
|
||||
RuntimeLevel runtimeLevel = RuntimeLevel.Run,
|
||||
bool currentUserIsAuthenticated = false,
|
||||
bool currentUserIsApproved = false)
|
||||
{
|
||||
var mockBackOfficeSecurityAccessor =
|
||||
CreateMockBackOfficeSecurityAccessor(currentUserIsAuthenticated, currentUserIsApproved);
|
||||
var mockRuntimeState = CreateMockRuntimeState(runtimeLevel);
|
||||
return new BackOfficeHandler(mockBackOfficeSecurityAccessor.Object, mockRuntimeState.Object);
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(
|
||||
bool currentUserIsAuthenticated, bool currentUserIsApproved)
|
||||
{
|
||||
var user = new UserBuilder()
|
||||
.WithIsApproved(currentUserIsApproved)
|
||||
.Build();
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.Setup(x => x.IsAuthenticated()).Returns(currentUserIsAuthenticated);
|
||||
if (currentUserIsAuthenticated)
|
||||
{
|
||||
mockBackOfficeSecurity.Setup(x => x.CurrentUser).Returns(user);
|
||||
}
|
||||
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static Mock<IRuntimeState> CreateMockRuntimeState(RuntimeLevel runtimeLevel)
|
||||
{
|
||||
var mockRuntimeState = new Mock<IRuntimeState>();
|
||||
mockRuntimeState.SetupGet(x => x.Level).Returns(runtimeLevel);
|
||||
return mockRuntimeState;
|
||||
}
|
||||
}
|
||||
@@ -1,178 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
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.Persistence.Querying;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class ContentPermissionsPublishBranchHandlerTests
|
||||
{
|
||||
private const int NodeId = 1000;
|
||||
private const int DescendentNodeId1 = 1001;
|
||||
private const int DescendentNodeId2 = 1002;
|
||||
|
||||
[Test]
|
||||
public async Task User_With_Access_To_All_Descendent_Nodes_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockUserService = CreateMockUserService(
|
||||
NodeId,
|
||||
new Dictionary<int, string[]> { { DescendentNodeId1, new[] { "A" } }, { DescendentNodeId2, new[] { "A" } } });
|
||||
var sut = CreateHandler(mockUserService.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
mockUserService.Verify(x => x.GetPermissionsForPath(It.IsAny<IUser>(), It.IsAny<string>()), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Without_Access_To_One_Descendent_Node_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockUserService = CreateMockUserService(
|
||||
NodeId,
|
||||
new Dictionary<int, string[]> { { DescendentNodeId1, new[] { "A" } }, { DescendentNodeId2, new[] { "B" } } });
|
||||
var sut = CreateHandler(mockUserService.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
mockUserService.Verify(x => x.GetPermissionsForPath(It.IsAny<IUser>(), It.IsAny<string>()), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Without_Access_To_First_Descendent_Node_Is_Not_Authorized_And_Checks_Exit_Early()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockUserService = CreateMockUserService(
|
||||
NodeId,
|
||||
new Dictionary<int, string[]> { { DescendentNodeId1, new[] { "B" } }, { DescendentNodeId2, new[] { "A" } } });
|
||||
var sut = CreateHandler(mockUserService.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
mockUserService.Verify(x => x.GetPermissionsForPath(It.IsAny<IUser>(), It.IsAny<string>()), Times.Exactly(1));
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext()
|
||||
{
|
||||
var requirement = new ContentPermissionsPublishBranchRequirement('A');
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = CreateContent(NodeId);
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private static Mock<IUserService> CreateMockUserService(
|
||||
int parentNodeId,
|
||||
Dictionary<int, string[]> descendendNodePermissionsForPath)
|
||||
{
|
||||
var mockUserService = new Mock<IUserService>();
|
||||
|
||||
mockUserService
|
||||
.Setup(x => x.GetPermissionsForPath(
|
||||
It.IsAny<IUser>(),
|
||||
It.Is<string>(y =>
|
||||
y ==
|
||||
$"{Constants.System.RootString},{parentNodeId.ToString(CultureInfo.InvariantCulture)},{DescendentNodeId1}")))
|
||||
.Returns(new EntityPermissionSet(
|
||||
parentNodeId,
|
||||
new EntityPermissionCollection(new List<EntityPermission>
|
||||
{
|
||||
new(1, parentNodeId, descendendNodePermissionsForPath[DescendentNodeId1]),
|
||||
})));
|
||||
mockUserService
|
||||
.Setup(x => x.GetPermissionsForPath(
|
||||
It.IsAny<IUser>(),
|
||||
It.Is<string>(y =>
|
||||
y ==
|
||||
$"{Constants.System.RootString},{parentNodeId.ToString(CultureInfo.InvariantCulture)},{DescendentNodeId1},{DescendentNodeId2}")))
|
||||
.Returns(new EntityPermissionSet(
|
||||
parentNodeId,
|
||||
new EntityPermissionCollection(new List<EntityPermission>
|
||||
{
|
||||
new(1, parentNodeId, descendendNodePermissionsForPath[DescendentNodeId2]),
|
||||
})));
|
||||
|
||||
return mockUserService;
|
||||
}
|
||||
|
||||
private ContentPermissionsPublishBranchHandler CreateHandler(IUserService userService, int nodeId)
|
||||
{
|
||||
var mockEntityService = CreateMockEntityService();
|
||||
var contentPermissions = CreateContentPermissions(mockEntityService.Object, userService, nodeId);
|
||||
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
|
||||
return new ContentPermissionsPublishBranchHandler(mockEntityService.Object, contentPermissions, mockBackOfficeSecurityAccessor.Object);
|
||||
}
|
||||
|
||||
private static Mock<IEntityService> CreateMockEntityService()
|
||||
{
|
||||
long totalRecords;
|
||||
var mockEntityService = new Mock<IEntityService>();
|
||||
mockEntityService
|
||||
.Setup(x => x.GetPagedDescendants(
|
||||
It.Is<int>(y => y == NodeId),
|
||||
It.Is<UmbracoObjectTypes>(y => y == UmbracoObjectTypes.Document),
|
||||
It.IsAny<long>(),
|
||||
It.IsAny<int>(),
|
||||
out totalRecords,
|
||||
It.IsAny<IQuery<IUmbracoEntity>>(),
|
||||
It.IsAny<Ordering>()))
|
||||
.Returns(new List<IEntitySlim>
|
||||
{
|
||||
new EntitySlim { Id = DescendentNodeId1, Path = $"-1,{NodeId},{DescendentNodeId1}" },
|
||||
new EntitySlim
|
||||
{
|
||||
Id = DescendentNodeId2, Path = $"-1,{NodeId},{DescendentNodeId1},{DescendentNodeId2}",
|
||||
},
|
||||
});
|
||||
return mockEntityService;
|
||||
}
|
||||
|
||||
private static ContentPermissions CreateContentPermissions(IEntityService entityService, IUserService userService, int nodeId)
|
||||
{
|
||||
var mockContentService = new Mock<IContentService>();
|
||||
mockContentService
|
||||
.Setup(x => x.GetById(It.Is<int>(y => y == nodeId)))
|
||||
.Returns(CreateContent(nodeId));
|
||||
|
||||
return new ContentPermissions(userService, mockContentService.Object, entityService, AppCaches.Disabled);
|
||||
}
|
||||
|
||||
private static IContent CreateContent(int nodeId)
|
||||
{
|
||||
var contentType = ContentTypeBuilder.CreateBasicContentType();
|
||||
return ContentBuilder.CreateBasicContent(contentType, nodeId);
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor()
|
||||
{
|
||||
var user = CreateUser();
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser() =>
|
||||
new UserBuilder()
|
||||
.Build();
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
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.Web.BackOffice.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class ContentPermissionsQueryStringHandlerTests
|
||||
{
|
||||
private const string QueryStringName = "id";
|
||||
private const int NodeId = 1000;
|
||||
private static readonly Guid s_nodeGuid = Guid.NewGuid();
|
||||
|
||||
private static readonly Udi s_nodeUdi =
|
||||
UdiParser.Parse($"umb://document/{s_nodeGuid.ToString().ToLowerInvariant().Replace("-", string.Empty)}");
|
||||
|
||||
[Test]
|
||||
public async Task Node_Id_From_Requirement_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor();
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Id_From_Requirement_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor();
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "B" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
AssertContentCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Id_Missing_From_Requirement_And_QueryString_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor("xxx");
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Integer_Id_From_QueryString_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
AssertContentCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "B" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
AssertContentCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
AssertContentCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "B" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
AssertContentCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
AssertContentCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "B" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
AssertContentCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Invalid_Id_From_QueryString_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: "invalid");
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(int? nodeId = null)
|
||||
{
|
||||
const char Permission = 'A';
|
||||
var requirement = nodeId.HasValue
|
||||
? new ContentPermissionsQueryStringRequirement(nodeId.Value, Permission)
|
||||
: new ContentPermissionsQueryStringRequirement(Permission);
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private static Mock<IHttpContextAccessor> CreateMockHttpContextAccessor(
|
||||
string queryStringName = QueryStringName,
|
||||
string queryStringValue = "")
|
||||
{
|
||||
var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
|
||||
var mockHttpContext = new Mock<HttpContext>();
|
||||
var mockHttpRequest = new Mock<HttpRequest>();
|
||||
var queryParams = new Dictionary<string, StringValues> { { queryStringName, queryStringValue } };
|
||||
mockHttpRequest.SetupGet(x => x.Query).Returns(new QueryCollection(queryParams));
|
||||
mockHttpContext.SetupGet(x => x.Request).Returns(mockHttpRequest.Object);
|
||||
mockHttpContext.SetupGet(x => x.Items).Returns(new Dictionary<object, object>());
|
||||
mockHttpContextAccessor.SetupGet(x => x.HttpContext).Returns(mockHttpContext.Object);
|
||||
return mockHttpContextAccessor;
|
||||
}
|
||||
|
||||
private ContentPermissionsQueryStringHandler CreateHandler(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
int nodeId,
|
||||
string[] permissionsForPath)
|
||||
{
|
||||
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
|
||||
var mockEntityService = CreateMockEntityService();
|
||||
var contentPermissions = CreateContentPermissions(mockEntityService.Object, nodeId, permissionsForPath);
|
||||
return new ContentPermissionsQueryStringHandler(
|
||||
mockBackOfficeSecurityAccessor.Object,
|
||||
httpContextAccessor,
|
||||
mockEntityService.Object,
|
||||
contentPermissions);
|
||||
}
|
||||
|
||||
private static Mock<IEntityService> CreateMockEntityService()
|
||||
{
|
||||
var mockEntityService = new Mock<IEntityService>();
|
||||
mockEntityService
|
||||
.Setup(x => x.GetId(It.Is<Udi>(y => y == s_nodeUdi)))
|
||||
.Returns(Attempt<int>.Succeed(NodeId));
|
||||
mockEntityService
|
||||
.Setup(x => x.GetId(
|
||||
It.Is<Guid>(y => y == s_nodeGuid),
|
||||
It.Is<UmbracoObjectTypes>(y => y == UmbracoObjectTypes.Document)))
|
||||
.Returns(Attempt<int>.Succeed(NodeId));
|
||||
return mockEntityService;
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor()
|
||||
{
|
||||
var user = CreateUser();
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser() =>
|
||||
new UserBuilder()
|
||||
.Build();
|
||||
|
||||
private static ContentPermissions CreateContentPermissions(
|
||||
IEntityService entityService,
|
||||
int nodeId,
|
||||
string[] permissionsForPath)
|
||||
{
|
||||
var mockUserService = new Mock<IUserService>();
|
||||
|
||||
mockUserService
|
||||
.Setup(x => x.GetPermissionsForPath(
|
||||
It.IsAny<IUser>(),
|
||||
It.Is<string>(y => y == $"{Constants.System.RootString},{nodeId.ToInvariantString()}")))
|
||||
.Returns(new EntityPermissionSet(
|
||||
nodeId,
|
||||
new EntityPermissionCollection(new List<EntityPermission> { new(1, nodeId, permissionsForPath) })));
|
||||
|
||||
var mockContentService = new Mock<IContentService>();
|
||||
mockContentService
|
||||
.Setup(x => x.GetById(It.Is<int>(y => y == nodeId)))
|
||||
.Returns(CreateContent(nodeId));
|
||||
|
||||
return new ContentPermissions(
|
||||
mockUserService.Object,
|
||||
mockContentService.Object,
|
||||
entityService,
|
||||
AppCaches.Disabled);
|
||||
}
|
||||
|
||||
private static IContent CreateContent(int nodeId)
|
||||
{
|
||||
var contentType = ContentTypeBuilder.CreateBasicContentType();
|
||||
return ContentBuilder.CreateBasicContent(contentType, nodeId);
|
||||
}
|
||||
|
||||
private static void AssertContentCached(Mock<IHttpContextAccessor> mockHttpContextAccessor) =>
|
||||
Assert.AreEqual(
|
||||
NodeId,
|
||||
((IContent)mockHttpContextAccessor.Object.HttpContext.Items[typeof(IContent).ToString()]).Id);
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
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.Web.BackOffice.Authorization;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class ContentPermissionsResourceHandlerTests
|
||||
{
|
||||
private const int NodeId = 1000;
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Node_Id_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, true);
|
||||
var sut = CreateHandler(NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Content_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
|
||||
var sut = CreateHandler(NodeId, new[] { "A" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Node_Id_Withou_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, true);
|
||||
var sut = CreateHandler(NodeId, new[] { "B" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Content_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
|
||||
var sut = CreateHandler(NodeId, new[] { "B" });
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(
|
||||
int nodeId,
|
||||
bool createWithNodeId = false)
|
||||
{
|
||||
var requirement = new ContentPermissionsResourceRequirement();
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var content = CreateContent(nodeId);
|
||||
var permissions = new List<char> { 'A' }.AsReadOnly();
|
||||
var resource = createWithNodeId
|
||||
? new ContentPermissionsResource(content, nodeId, permissions)
|
||||
: new ContentPermissionsResource(content, permissions);
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private static IContent CreateContent(int nodeId)
|
||||
{
|
||||
var contentType = ContentTypeBuilder.CreateBasicContentType();
|
||||
return ContentBuilder.CreateBasicContent(contentType, nodeId);
|
||||
}
|
||||
|
||||
private ContentPermissionsResourceHandler CreateHandler(int nodeId, string[] permissionsForPath)
|
||||
{
|
||||
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
|
||||
var contentPermissions = CreateContentPermissions(nodeId, permissionsForPath);
|
||||
return new ContentPermissionsResourceHandler(mockBackOfficeSecurityAccessor.Object, contentPermissions);
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor()
|
||||
{
|
||||
var user = CreateUser();
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser() =>
|
||||
new UserBuilder()
|
||||
.Build();
|
||||
|
||||
private static ContentPermissions CreateContentPermissions(int nodeId, string[] permissionsForPath)
|
||||
{
|
||||
var mockUserService = new Mock<IUserService>();
|
||||
|
||||
mockUserService
|
||||
.Setup(x => x.GetPermissionsForPath(
|
||||
It.IsAny<IUser>(),
|
||||
It.Is<string>(y => y == $"{Constants.System.RootString},{nodeId.ToInvariantString()}")))
|
||||
.Returns(new EntityPermissionSet(
|
||||
nodeId,
|
||||
new EntityPermissionCollection(new List<EntityPermission> { new(1, nodeId, permissionsForPath) })));
|
||||
|
||||
var mockContentService = new Mock<IContentService>();
|
||||
mockContentService
|
||||
.Setup(x => x.GetById(It.Is<int>(y => y == nodeId)))
|
||||
.Returns(CreateContent(nodeId));
|
||||
|
||||
var mockEntityService = new Mock<IEntityService>();
|
||||
return new ContentPermissions(
|
||||
mockUserService.Object,
|
||||
mockContentService.Object,
|
||||
mockEntityService.Object,
|
||||
AppCaches.Disabled);
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
using Umbraco.Cms.Web.BackOffice.Security;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class DenyLocalLoginHandlerTests
|
||||
{
|
||||
[Test]
|
||||
public async Task With_Deny_Local_Login_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Without_Deny_Local_Login_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler();
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext()
|
||||
{
|
||||
var requirement = new DenyLocalLoginRequirement();
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private DenyLocalLoginHandler CreateHandler(bool denyLocalLogin = false)
|
||||
{
|
||||
var mockBackOfficeExternalLoginProviders = CreateMockBackOfficeExternalLoginProviders(denyLocalLogin);
|
||||
|
||||
return new DenyLocalLoginHandler(mockBackOfficeExternalLoginProviders.Object);
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeExternalLoginProviders> CreateMockBackOfficeExternalLoginProviders(
|
||||
bool denyLocalLogin)
|
||||
{
|
||||
var mockBackOfficeExternalLoginProviders = new Mock<IBackOfficeExternalLoginProviders>();
|
||||
mockBackOfficeExternalLoginProviders.Setup(x => x.HasDenyLocalLogin()).Returns(denyLocalLogin);
|
||||
return mockBackOfficeExternalLoginProviders;
|
||||
}
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
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.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class MediaPermissionsQueryStringHandlerTests
|
||||
{
|
||||
private const string QueryStringName = "id";
|
||||
private const int NodeId = 1000;
|
||||
private static readonly Guid s_nodeGuid = Guid.NewGuid();
|
||||
|
||||
private static readonly Udi s_nodeUdi =
|
||||
UdiParser.Parse($"umb://document/{s_nodeGuid.ToString().ToLowerInvariant().Replace("-", string.Empty)}");
|
||||
|
||||
[Test]
|
||||
public async Task Node_Id_Missing_From_QueryString_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor("xxx");
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Integer_Id_From_QueryString_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
AssertMediaCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Integer_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, 1001);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
AssertMediaCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
AssertMediaCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, 1001);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
AssertMediaCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
AssertMediaCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, 1001);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
AssertMediaCached(mockHttpContextAccessor);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Node_Invalid_Id_From_QueryString_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: "invalid");
|
||||
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext()
|
||||
{
|
||||
var requirement = new MediaPermissionsQueryStringRequirement(QueryStringName);
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private static Mock<IHttpContextAccessor> CreateMockHttpContextAccessor(
|
||||
string queryStringName = QueryStringName,
|
||||
string queryStringValue = "")
|
||||
{
|
||||
var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
|
||||
var mockHttpContext = new Mock<HttpContext>();
|
||||
var mockHttpRequest = new Mock<HttpRequest>();
|
||||
var queryParams = new Dictionary<string, StringValues> { { queryStringName, queryStringValue } };
|
||||
mockHttpRequest.SetupGet(x => x.Query).Returns(new QueryCollection(queryParams));
|
||||
mockHttpContext.SetupGet(x => x.Request).Returns(mockHttpRequest.Object);
|
||||
mockHttpContext.SetupGet(x => x.Items).Returns(new Dictionary<object, object>());
|
||||
mockHttpContextAccessor.SetupGet(x => x.HttpContext).Returns(mockHttpContext.Object);
|
||||
return mockHttpContextAccessor;
|
||||
}
|
||||
|
||||
private MediaPermissionsQueryStringHandler CreateHandler(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
int nodeId,
|
||||
int startMediaId = -1)
|
||||
{
|
||||
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(startMediaId);
|
||||
var mockEntityService = CreateMockEntityService();
|
||||
var mediaPermissions = CreateMediaPermissions(mockEntityService.Object, nodeId);
|
||||
return new MediaPermissionsQueryStringHandler(
|
||||
mockBackOfficeSecurityAccessor.Object,
|
||||
httpContextAccessor,
|
||||
mockEntityService.Object,
|
||||
mediaPermissions);
|
||||
}
|
||||
|
||||
private static Mock<IEntityService> CreateMockEntityService()
|
||||
{
|
||||
var mockEntityService = new Mock<IEntityService>();
|
||||
mockEntityService
|
||||
.Setup(x => x.GetId(It.Is<Udi>(y => y == s_nodeUdi)))
|
||||
.Returns(Attempt<int>.Succeed(NodeId));
|
||||
mockEntityService
|
||||
.Setup(x => x.GetId(
|
||||
It.Is<Guid>(y => y == s_nodeGuid),
|
||||
It.Is<UmbracoObjectTypes>(y => y == UmbracoObjectTypes.Document)))
|
||||
.Returns(Attempt<int>.Succeed(NodeId));
|
||||
return mockEntityService;
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(int startMediaId)
|
||||
{
|
||||
var user = CreateUser(startMediaId);
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser(int startMediaId) =>
|
||||
new UserBuilder()
|
||||
.WithStartMediaId(startMediaId)
|
||||
.Build();
|
||||
|
||||
private static MediaPermissions CreateMediaPermissions(IEntityService entityService, int nodeId)
|
||||
{
|
||||
var mockMediaService = new Mock<IMediaService>();
|
||||
mockMediaService
|
||||
.Setup(x => x.GetById(It.Is<int>(y => y == nodeId)))
|
||||
.Returns(CreateMedia(nodeId));
|
||||
|
||||
return new MediaPermissions(mockMediaService.Object, entityService, AppCaches.Disabled);
|
||||
}
|
||||
|
||||
private static IMedia CreateMedia(int nodeId)
|
||||
{
|
||||
var mediaType = MediaTypeBuilder.CreateSimpleMediaType("image", "Image");
|
||||
return MediaBuilder.CreateSimpleMedia(mediaType, "Test image", -1, nodeId);
|
||||
}
|
||||
|
||||
private static void AssertMediaCached(Mock<IHttpContextAccessor> mockHttpContextAccessor) =>
|
||||
Assert.AreEqual(
|
||||
NodeId,
|
||||
((IMedia)mockHttpContextAccessor.Object.HttpContext.Items[typeof(IMedia).ToString()]).Id);
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
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.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class MediaPermissionsResourceHandlerTests
|
||||
{
|
||||
private const int NodeId = 1000;
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Node_Id_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, true);
|
||||
var sut = CreateHandler(NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Media_With_Permission_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
|
||||
var sut = CreateHandler(NodeId);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Node_Id_Withou_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, true);
|
||||
var sut = CreateHandler(NodeId, 1001);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Resource_With_Media_Without_Permission_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
|
||||
var sut = CreateHandler(NodeId, 1001);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(
|
||||
int nodeId,
|
||||
bool createWithNodeId = false)
|
||||
{
|
||||
var requirement = new MediaPermissionsResourceRequirement();
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var media = CreateMedia(nodeId);
|
||||
var resource = createWithNodeId
|
||||
? new MediaPermissionsResource(nodeId)
|
||||
: new MediaPermissionsResource(media);
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private static IMedia CreateMedia(int nodeId)
|
||||
{
|
||||
var mediaType = MediaTypeBuilder.CreateSimpleMediaType("image", "Image");
|
||||
return MediaBuilder.CreateSimpleMedia(mediaType, "Test image", -1, nodeId);
|
||||
}
|
||||
|
||||
private MediaPermissionsResourceHandler CreateHandler(int nodeId, int startMediaId = -1)
|
||||
{
|
||||
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(startMediaId);
|
||||
var contentPermissions = CreateMediaPermissions(nodeId);
|
||||
return new MediaPermissionsResourceHandler(mockBackOfficeSecurityAccessor.Object, contentPermissions);
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(int startMediaId)
|
||||
{
|
||||
var user = CreateUser(startMediaId);
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser(int startMediaId) =>
|
||||
new UserBuilder()
|
||||
.WithStartMediaId(startMediaId)
|
||||
.Build();
|
||||
|
||||
private static MediaPermissions CreateMediaPermissions(int nodeId)
|
||||
{
|
||||
var mockMediaService = new Mock<IMediaService>();
|
||||
mockMediaService
|
||||
.Setup(x => x.GetById(It.Is<int>(y => y == nodeId)))
|
||||
.Returns(CreateMedia(nodeId));
|
||||
|
||||
var mockEntityService = new Mock<IEntityService>();
|
||||
return new MediaPermissions(mockMediaService.Object, mockEntityService.Object, AppCaches.Disabled);
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class SectionHandlerTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Unauthorized_User_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler();
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_With_Section_Access_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(true, true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Without_Section_Access_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext()
|
||||
{
|
||||
var requirement = new SectionRequirement(Constants.Applications.Content, Constants.Applications.Media);
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private SectionHandler CreateHandler(bool userIsAuthorized = false, bool userCanAccessContentSection = false)
|
||||
{
|
||||
var mockBackOfficeSecurityAccessor =
|
||||
CreateMockBackOfficeSecurityAccessor(userIsAuthorized, userCanAccessContentSection);
|
||||
|
||||
return new SectionHandler(mockBackOfficeSecurityAccessor.Object);
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(
|
||||
bool userIsAuthorized,
|
||||
bool userCanAccessContentSection)
|
||||
{
|
||||
var user = CreateUser();
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(userIsAuthorized ? user : null);
|
||||
mockBackOfficeSecurity
|
||||
.Setup(x => x.UserHasSectionAccess(
|
||||
Constants.Applications.Content,
|
||||
It.Is<IUser>(y => y.Username == user.Username)))
|
||||
.Returns(userCanAccessContentSection);
|
||||
mockBackOfficeSecurity
|
||||
.Setup(x => x.UserHasSectionAccess(
|
||||
Constants.Applications.Media,
|
||||
It.Is<IUser>(y => y.Username == user.Username)))
|
||||
.Returns(false);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser() =>
|
||||
new UserBuilder()
|
||||
.Build();
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Trees;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class TreeHandlerTests
|
||||
{
|
||||
private const string Tree1Alias = "Tree1";
|
||||
private const string Tree2Alias = "Tree2";
|
||||
|
||||
[Test]
|
||||
public async Task Unauthorized_User_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler();
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_With_Access_To_Tree_Section_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(true, true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Without_Access_To_Tree_Section_Is_Not_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext()
|
||||
{
|
||||
var requirement = new TreeRequirement(Tree1Alias, Tree2Alias);
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private TreeHandler CreateHandler(bool userIsAuthorized = false, bool userCanAccessContentSection = false)
|
||||
{
|
||||
var mockTreeService = CreateMockTreeService();
|
||||
var mockBackOfficeSecurityAccessor =
|
||||
CreateMockBackOfficeSecurityAccessor(userIsAuthorized, userCanAccessContentSection);
|
||||
|
||||
return new TreeHandler(mockTreeService.Object, mockBackOfficeSecurityAccessor.Object);
|
||||
}
|
||||
|
||||
private static Mock<ITreeService> CreateMockTreeService()
|
||||
{
|
||||
var mockTreeService = new Mock<ITreeService>();
|
||||
mockTreeService
|
||||
.Setup(x => x.GetByAlias(It.Is<string>(y => y == Tree1Alias)))
|
||||
.Returns(CreateTree(Tree1Alias, Constants.Applications.Content));
|
||||
mockTreeService
|
||||
.Setup(x => x.GetByAlias(It.Is<string>(y => y == Tree2Alias)))
|
||||
.Returns(CreateTree(Tree2Alias, Constants.Applications.Media));
|
||||
return mockTreeService;
|
||||
}
|
||||
|
||||
private static Tree CreateTree(string alias, string sectionAlias) =>
|
||||
new TreeBuilder()
|
||||
.WithAlias(alias)
|
||||
.WithSectionAlias(sectionAlias)
|
||||
.Build();
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(
|
||||
bool userIsAuthorized,
|
||||
bool userCanAccessContentSection)
|
||||
{
|
||||
var user = CreateUser();
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(userIsAuthorized ? user : null);
|
||||
mockBackOfficeSecurity
|
||||
.Setup(x => x.UserHasSectionAccess(
|
||||
Constants.Applications.Content,
|
||||
It.Is<IUser>(y => y.Username == user.Username)))
|
||||
.Returns(userCanAccessContentSection);
|
||||
mockBackOfficeSecurity
|
||||
.Setup(x => x.UserHasSectionAccess(
|
||||
Constants.Applications.Media,
|
||||
It.Is<IUser>(y => y.Username == user.Username)))
|
||||
.Returns(false);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser() => new UserBuilder()
|
||||
.Build();
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
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;
|
||||
using Umbraco.Cms.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
public class UserGroupHandlerTests
|
||||
{
|
||||
private const string QueryStringName = "id";
|
||||
|
||||
private const int Group1Id = 1;
|
||||
private const string Group1Alias = "group1";
|
||||
private const int Group2Id = 2;
|
||||
private const string Group2Alias = "group2";
|
||||
private const int Group3Id = 3;
|
||||
private const string Group3Alias = "group3";
|
||||
|
||||
[Test]
|
||||
public async Task Missing_QueryString_Value_Is_Authorized()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler();
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Admin_User_Is_Authorised()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(Group1Id.ToString(), true);
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Matching_Single_Requested_Group_Id_Is_Authorised()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(Group1Id.ToString());
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Matching_Only_One_Of_Requested_Group_Ids_Is_NOT_Authorised()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler($"{Group1Id},{Group2Id}");
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsTrue(authHandlerContext.HasFailed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Not_Matching_Single_Requested_Group_Id_Is_Not_Authorised()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler(Group2Id.ToString());
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task User_Not_Matching_Any_Of_Requested_Group_Ids_Is_Not_Authorised()
|
||||
{
|
||||
var authHandlerContext = CreateAuthorizationHandlerContext();
|
||||
var sut = CreateHandler($"{Group2Id},{Group3Id}");
|
||||
|
||||
await sut.HandleAsync(authHandlerContext);
|
||||
|
||||
Assert.IsFalse(authHandlerContext.HasSucceeded);
|
||||
}
|
||||
|
||||
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext()
|
||||
{
|
||||
var requirement = new UserGroupRequirement();
|
||||
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
|
||||
var resource = new object();
|
||||
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
|
||||
}
|
||||
|
||||
private UserGroupHandler CreateHandler(string queryStringValue = "", bool userIsAdmin = false)
|
||||
{
|
||||
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue);
|
||||
|
||||
var mockUserService = CreateMockUserService();
|
||||
|
||||
var mockContentService = new Mock<IContentService>();
|
||||
var mockMediaService = new Mock<IMediaService>();
|
||||
var mockEntityService = new Mock<IEntityService>();
|
||||
|
||||
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(userIsAdmin);
|
||||
|
||||
return new UserGroupHandler(
|
||||
mockHttpContextAccessor.Object,
|
||||
mockUserService.Object,
|
||||
mockContentService.Object,
|
||||
mockMediaService.Object,
|
||||
mockEntityService.Object,
|
||||
mockBackOfficeSecurityAccessor.Object,
|
||||
AppCaches.Disabled);
|
||||
}
|
||||
|
||||
private static Mock<IHttpContextAccessor> CreateMockHttpContextAccessor(string queryStringValue)
|
||||
{
|
||||
var mockHttpContextAccessor = new Mock<IHttpContextAccessor>();
|
||||
var mockHttpContext = new Mock<HttpContext>();
|
||||
var mockHttpRequest = new Mock<HttpRequest>();
|
||||
var queryParams = new Dictionary<string, StringValues> { { QueryStringName, queryStringValue } };
|
||||
mockHttpRequest.SetupGet(x => x.Query).Returns(new QueryCollection(queryParams));
|
||||
mockHttpContext.SetupGet(x => x.Request).Returns(mockHttpRequest.Object);
|
||||
mockHttpContextAccessor.SetupGet(x => x.HttpContext).Returns(mockHttpContext.Object);
|
||||
return mockHttpContextAccessor;
|
||||
}
|
||||
|
||||
private Mock<IUserService> CreateMockUserService()
|
||||
{
|
||||
var mockUserService = new Mock<IUserService>();
|
||||
mockUserService
|
||||
.Setup(x => x.GetAllUserGroups(It.Is<int[]>(y => y.Length == 1 && y[0] == Group1Id)))
|
||||
.Returns(new List<IUserGroup> { CreateUserGroup(Group1Id, Group1Alias) });
|
||||
mockUserService
|
||||
.Setup(x => x.GetAllUserGroups(It.Is<int[]>(y => y.Length == 1 && y[0] == Group2Id)))
|
||||
.Returns(new List<IUserGroup> { CreateUserGroup(Group2Id, Group2Alias) });
|
||||
mockUserService
|
||||
.Setup(x => x.GetAllUserGroups(It.Is<int[]>(y => y.Length == 2 && y[0] == Group1Id && y[1] == Group2Id)))
|
||||
.Returns(new List<IUserGroup>
|
||||
{
|
||||
CreateUserGroup(Group1Id, Group1Alias),
|
||||
CreateUserGroup(Group2Id, Group2Alias),
|
||||
});
|
||||
mockUserService
|
||||
.Setup(x => x.GetAllUserGroups(It.Is<int[]>(y => y.Length == 2 && y[0] == Group2Id && y[1] == Group3Id)))
|
||||
.Returns(new List<IUserGroup>
|
||||
{
|
||||
CreateUserGroup(Group2Id, Group2Alias),
|
||||
CreateUserGroup(Group3Id, Group3Alias),
|
||||
});
|
||||
return mockUserService;
|
||||
}
|
||||
|
||||
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(bool userIsAdmin)
|
||||
{
|
||||
var user = CreateUser(userIsAdmin);
|
||||
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
|
||||
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
|
||||
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
|
||||
mockBackOfficeSecurityAccessor.Setup(x => x.BackOfficeSecurity).Returns(mockBackOfficeSecurity.Object);
|
||||
return mockBackOfficeSecurityAccessor;
|
||||
}
|
||||
|
||||
private static User CreateUser(bool isAdmin = false) =>
|
||||
new UserBuilder()
|
||||
.AddUserGroup()
|
||||
.WithAlias(isAdmin ? Constants.Security.AdminGroupAlias : Group1Alias)
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
private IUserGroup CreateUserGroup(int id, string alias) =>
|
||||
new UserGroupBuilder()
|
||||
.WithId(id)
|
||||
.WithAlias(alias)
|
||||
.Build();
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Trees;
|
||||
using Umbraco.Cms.Web.BackOffice.Trees;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.CollectionBuilders;
|
||||
|
||||
public class TreeCollectionBuilderTests
|
||||
{
|
||||
[Test]
|
||||
public void Adding_Tree_To_Collection_Builder()
|
||||
{
|
||||
var collectionBuilder = new TreeCollectionBuilder();
|
||||
var treeDefinition = new Tree(
|
||||
0,
|
||||
"test",
|
||||
"test",
|
||||
"test",
|
||||
"test",
|
||||
TreeUse.Main,
|
||||
typeof(LanguageTreeController),
|
||||
false);
|
||||
|
||||
collectionBuilder.AddTree(treeDefinition);
|
||||
var collection = collectionBuilder.CreateCollection(null);
|
||||
|
||||
Assert.AreEqual(1, collection.Count);
|
||||
Assert.AreEqual(treeDefinition, collection.FirstOrDefault());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Remove_Tree_From_Collection_Builder()
|
||||
{
|
||||
var collectionBuilder = new TreeCollectionBuilder();
|
||||
var treeDefinition = new Tree(0, "test", "test", "test", "test", TreeUse.Main, typeof(LanguageTreeController), false);
|
||||
|
||||
collectionBuilder.AddTree(treeDefinition);
|
||||
collectionBuilder.RemoveTreeController<LanguageTreeController>();
|
||||
var collection = collectionBuilder.CreateCollection(null);
|
||||
|
||||
Assert.AreEqual(0, collection.Count);
|
||||
}
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Dictionary;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.PropertyEditors;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Controllers;
|
||||
|
||||
[TestFixture]
|
||||
public class ContentControllerTests
|
||||
{
|
||||
[Test]
|
||||
public void Root_Node_With_Domains_Causes_No_Warning()
|
||||
{
|
||||
// Setup domain service
|
||||
var domainServiceMock = new Mock<IDomainService>();
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(1060, It.IsAny<bool>()))
|
||||
.Returns(new[] { new UmbracoDomain("/", "da-dk"), new UmbracoDomain("/en", "en-us") });
|
||||
|
||||
// Create content, we need to specify and ID in order to be able to configure domain service
|
||||
var rootNode = new ContentBuilder()
|
||||
.WithContentType(CreateContentType())
|
||||
.WithId(1060)
|
||||
.AddContentCultureInfosCollection()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("da-dk")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("en-us")
|
||||
.Done()
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
var culturesPublished = new[] { "en-us", "da-dk" };
|
||||
var notifications = new SimpleNotificationModel();
|
||||
|
||||
var contentController = CreateContentController(domainServiceMock.Object);
|
||||
contentController.AddDomainWarnings(rootNode, culturesPublished, notifications);
|
||||
|
||||
Assert.IsEmpty(notifications.Notifications);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Node_With_Single_Published_Culture_Causes_No_Warning()
|
||||
{
|
||||
var domainServiceMock = new Mock<IDomainService>();
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(It.IsAny<int>(), It.IsAny<bool>()))
|
||||
.Returns(Enumerable.Empty<IDomain>());
|
||||
|
||||
var rootNode = new ContentBuilder()
|
||||
.WithContentType(CreateContentType())
|
||||
.WithId(1060)
|
||||
.AddContentCultureInfosCollection()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("da-dk")
|
||||
.Done()
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
var culturesPublished = new[] { "da-dk" };
|
||||
var notifications = new SimpleNotificationModel();
|
||||
|
||||
var contentController = CreateContentController(domainServiceMock.Object);
|
||||
contentController.AddDomainWarnings(rootNode, culturesPublished, notifications);
|
||||
|
||||
Assert.IsEmpty(notifications.Notifications);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Root_Node_Without_Domains_Causes_SingleWarning()
|
||||
{
|
||||
var domainServiceMock = new Mock<IDomainService>();
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(It.IsAny<int>(), It.IsAny<bool>()))
|
||||
.Returns(Enumerable.Empty<IDomain>());
|
||||
|
||||
var rootNode = new ContentBuilder()
|
||||
.WithContentType(CreateContentType())
|
||||
.WithId(1060)
|
||||
.AddContentCultureInfosCollection()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("da-dk")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("en-us")
|
||||
.Done()
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
var culturesPublished = new[] { "en-us", "da-dk" };
|
||||
var notifications = new SimpleNotificationModel();
|
||||
|
||||
var contentController = CreateContentController(domainServiceMock.Object);
|
||||
contentController.AddDomainWarnings(rootNode, culturesPublished, notifications);
|
||||
Assert.AreEqual(1, notifications.Notifications.Count(x => x.NotificationType == NotificationStyle.Warning));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void One_Warning_Per_Culture_Being_Published()
|
||||
{
|
||||
var domainServiceMock = new Mock<IDomainService>();
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(It.IsAny<int>(), It.IsAny<bool>()))
|
||||
.Returns(new[] { new UmbracoDomain("/", "da-dk") });
|
||||
|
||||
var rootNode = new ContentBuilder()
|
||||
.WithContentType(CreateContentType())
|
||||
.WithId(1060)
|
||||
.AddContentCultureInfosCollection()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("da-dk")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("en-us")
|
||||
.Done()
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
var culturesPublished = new[] { "en-us", "da-dk", "nl-bk", "se-sv" };
|
||||
var notifications = new SimpleNotificationModel();
|
||||
|
||||
var contentController = CreateContentController(domainServiceMock.Object);
|
||||
contentController.AddDomainWarnings(rootNode, culturesPublished, notifications);
|
||||
Assert.AreEqual(3, notifications.Notifications.Count(x => x.NotificationType == NotificationStyle.Warning));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Ancestor_Domains_Counts()
|
||||
{
|
||||
var rootId = 1060;
|
||||
var level1Id = 1061;
|
||||
var level2Id = 1062;
|
||||
var level3Id = 1063;
|
||||
|
||||
var domainServiceMock = new Mock<IDomainService>();
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(rootId, It.IsAny<bool>()))
|
||||
.Returns(new[] { new UmbracoDomain("/", "da-dk") });
|
||||
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(level1Id, It.IsAny<bool>()))
|
||||
.Returns(new[] { new UmbracoDomain("/en", "en-us") });
|
||||
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(level2Id, It.IsAny<bool>()))
|
||||
.Returns(new[] { new UmbracoDomain("/se", "se-sv"), new UmbracoDomain("/nl", "nl-bk") });
|
||||
|
||||
var level3Node = new ContentBuilder()
|
||||
.WithContentType(CreateContentType())
|
||||
.WithId(level3Id)
|
||||
.WithPath($"-1,{rootId},{level1Id},{level2Id},{level3Id}")
|
||||
.AddContentCultureInfosCollection()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("da-dk")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("en-us")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("se-sv")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("nl-bk")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("de-de")
|
||||
.Done()
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
var culturesPublished = new[] { "en-us", "da-dk", "nl-bk", "se-sv", "de-de" };
|
||||
|
||||
var contentController = CreateContentController(domainServiceMock.Object);
|
||||
var notifications = new SimpleNotificationModel();
|
||||
|
||||
contentController.AddDomainWarnings(level3Node, culturesPublished, notifications);
|
||||
|
||||
// We expect one error because all domains except "de-de" is registered somewhere in the ancestor path
|
||||
Assert.AreEqual(1, notifications.Notifications.Count(x => x.NotificationType == NotificationStyle.Warning));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Only_Warns_About_Cultures_Being_Published()
|
||||
{
|
||||
var domainServiceMock = new Mock<IDomainService>();
|
||||
domainServiceMock.Setup(x => x.GetAssignedDomains(It.IsAny<int>(), It.IsAny<bool>()))
|
||||
.Returns(new[] { new UmbracoDomain("/", "da-dk") });
|
||||
|
||||
var rootNode = new ContentBuilder()
|
||||
.WithContentType(CreateContentType())
|
||||
.WithId(1060)
|
||||
.AddContentCultureInfosCollection()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("da-dk")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("en-us")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("se-sv")
|
||||
.Done()
|
||||
.AddCultureInfos()
|
||||
.WithCultureIso("de-de")
|
||||
.Done()
|
||||
.Done()
|
||||
.Build();
|
||||
|
||||
var culturesPublished = new[] { "en-us", "se-sv" };
|
||||
var notifications = new SimpleNotificationModel();
|
||||
|
||||
var contentController = CreateContentController(domainServiceMock.Object);
|
||||
contentController.AddDomainWarnings(rootNode, culturesPublished, notifications);
|
||||
|
||||
// We only get two errors, one for each culture being published, so no errors from previously published cultures.
|
||||
Assert.AreEqual(2, notifications.Notifications.Count(x => x.NotificationType == NotificationStyle.Warning));
|
||||
}
|
||||
|
||||
private ContentController CreateContentController(IDomainService domainService)
|
||||
{
|
||||
// We have to configure ILocalizedTextService to return a new string every time Localize is called
|
||||
// Otherwise it won't add the notification because it skips dupes
|
||||
var localizedTextServiceMock = new Mock<ILocalizedTextService>();
|
||||
localizedTextServiceMock.Setup(x => x.Localize(
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<CultureInfo>(),
|
||||
It.IsAny<IDictionary<string, string>>()))
|
||||
.Returns(() => Guid.NewGuid().ToString());
|
||||
|
||||
var controller = new ContentController(
|
||||
Mock.Of<ICultureDictionary>(),
|
||||
NullLoggerFactory.Instance,
|
||||
Mock.Of<IShortStringHelper>(),
|
||||
Mock.Of<IEventMessagesFactory>(),
|
||||
localizedTextServiceMock.Object,
|
||||
new PropertyEditorCollection(new DataEditorCollection(() => null)),
|
||||
Mock.Of<IContentService>(),
|
||||
Mock.Of<IUserService>(),
|
||||
Mock.Of<IBackOfficeSecurityAccessor>(),
|
||||
Mock.Of<IContentTypeService>(),
|
||||
Mock.Of<IUmbracoMapper>(),
|
||||
Mock.Of<IPublishedUrlProvider>(),
|
||||
domainService,
|
||||
Mock.Of<IDataTypeService>(),
|
||||
Mock.Of<ILocalizationService>(),
|
||||
Mock.Of<IFileService>(),
|
||||
Mock.Of<INotificationService>(),
|
||||
new ActionCollection(() => null),
|
||||
Mock.Of<ISqlContext>(),
|
||||
Mock.Of<IJsonSerializer>(),
|
||||
Mock.Of<ICoreScopeProvider>(),
|
||||
Mock.Of<IAuthorizationService>(),
|
||||
Mock.Of<IContentVersionService>(),
|
||||
Mock.Of<ICultureImpactFactory>(),
|
||||
Mock.Of<IUserGroupService>(),
|
||||
new OptionsWrapper<ContentSettings>(new ContentSettings()));
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
private IContentType CreateContentType() =>
|
||||
new ContentTypeBuilder().WithContentVariation(ContentVariation.Culture).Build();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using AutoFixture.NUnit3;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Controllers;
|
||||
|
||||
[TestFixture]
|
||||
public class UsersControllerTests
|
||||
{
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public void PostUnlockUsers_When_User_Lockout_Update_Fails_Expect_Failure_Response(
|
||||
[Frozen] IBackOfficeUserManager backOfficeUserManager,
|
||||
UsersController sut,
|
||||
BackOfficeIdentityUser user,
|
||||
int[] userIds,
|
||||
string expectedMessage)
|
||||
{
|
||||
Mock.Get(backOfficeUserManager)
|
||||
.Setup(x => x.FindByIdAsync(It.IsAny<string>()))
|
||||
.ReturnsAsync(user);
|
||||
|
||||
var result = sut.PostUnlockUsers(userIds).Result as ObjectResult;
|
||||
Assert.AreEqual(StatusCodes.Status400BadRequest, result.StatusCode);
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Extensions;
|
||||
|
||||
[TestFixture]
|
||||
public class ModelStateExtensionsTests
|
||||
{
|
||||
[Test]
|
||||
public void Get_Cultures_With_Errors()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); // invariant property
|
||||
ms.AddPropertyError(new ValidationResult("title missing"), "title", "en-US"); // variant property
|
||||
|
||||
var result = ms.GetVariantsWithErrors("en-US");
|
||||
|
||||
// even though there are 2 errors, they are both for en-US since that is the default language and one of the errors is for an invariant property
|
||||
Assert.AreEqual(1, result.Count);
|
||||
Assert.AreEqual("en-US", result[0].culture);
|
||||
|
||||
ms = new ModelStateDictionary();
|
||||
ms.AddVariantValidationError("en-US", null, "generic culture error");
|
||||
|
||||
result = ms.GetVariantsWithErrors("en-US");
|
||||
|
||||
Assert.AreEqual(1, result.Count);
|
||||
Assert.AreEqual("en-US", result[0].culture);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Cultures_With_Property_Errors()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); // invariant property
|
||||
ms.AddPropertyError(new ValidationResult("title missing"), "title", "en-US"); // variant property
|
||||
|
||||
var result = ms.GetVariantsWithPropertyErrors("en-US");
|
||||
|
||||
// even though there are 2 errors, they are both for en-US since that is the default language and one of the errors is for an invariant property
|
||||
Assert.AreEqual(1, result.Count);
|
||||
Assert.AreEqual("en-US", result[0].culture);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_Invariant_Property_Error()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null); // invariant property
|
||||
|
||||
Assert.AreEqual("_Properties.headerImage.invariant.null", ms.Keys.First());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_Variant_Property_Error()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", "en-US"); // variant property
|
||||
|
||||
Assert.AreEqual("_Properties.headerImage.en-US.null", ms.Keys.First());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_Invariant_Segment_Property_Error()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", null, "mySegment"); // invariant/segment property
|
||||
|
||||
Assert.AreEqual("_Properties.headerImage.invariant.mySegment", ms.Keys.First());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_Variant_Segment_Property_Error()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image"), "headerImage", "en-US", "mySegment"); // variant/segment property
|
||||
|
||||
Assert.AreEqual("_Properties.headerImage.en-US.mySegment", ms.Keys.First());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_Invariant_Segment_Field_Property_Error()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image", new[] { "myField" }), "headerImage", null, "mySegment"); // invariant/segment property
|
||||
|
||||
Assert.AreEqual("_Properties.headerImage.invariant.mySegment.myField", ms.Keys.First());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_Variant_Segment_Field_Property_Error()
|
||||
{
|
||||
var ms = new ModelStateDictionary();
|
||||
var localizationService = new Mock<ILocalizationService>();
|
||||
localizationService.Setup(x => x.GetDefaultLanguageIsoCode()).Returns("en-US");
|
||||
|
||||
ms.AddPropertyError(new ValidationResult("no header image", new[] { "myField" }), "headerImage", "en-US", "mySegment"); // variant/segment property
|
||||
|
||||
Assert.AreEqual("_Properties.headerImage.en-US.mySegment.myField", ms.Keys.First());
|
||||
}
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Filters;
|
||||
|
||||
[TestFixture]
|
||||
public class AppendUserModifiedHeaderAttributeTests
|
||||
{
|
||||
[Test]
|
||||
public void Appends_Header_When_No_User_Parameter_Provider()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext();
|
||||
var attribute = new AppendUserModifiedHeaderAttribute();
|
||||
|
||||
// Act
|
||||
attribute.OnActionExecuting(context);
|
||||
|
||||
// Assert
|
||||
context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue);
|
||||
Assert.AreEqual("1", headerValue[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Does_Not_Append_Header_If_Already_Exists()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext("0");
|
||||
var attribute = new AppendUserModifiedHeaderAttribute();
|
||||
|
||||
// Act
|
||||
attribute.OnActionExecuting(context);
|
||||
|
||||
// Assert
|
||||
context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue);
|
||||
Assert.AreEqual("0", headerValue[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Does_Not_Append_Header_When_User_Id_Parameter_Provided_And_Does_Not_Match_Current_User()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(actionArgument: new KeyValuePair<string, object>("UserId", 99));
|
||||
var userIdParameter = "UserId";
|
||||
var attribute = new AppendUserModifiedHeaderAttribute(userIdParameter);
|
||||
|
||||
// Act
|
||||
attribute.OnActionExecuting(context);
|
||||
|
||||
// Assert
|
||||
Assert.IsFalse(context.HttpContext.Response.Headers.ContainsKey("X-Umb-User-Modified"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Appends_Header_When_User_Id_Parameter_Provided_And_Does_Not_Match_Current_User()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(actionArgument: new KeyValuePair<string, object>("UserId", 100));
|
||||
var userIdParameter = "UserId";
|
||||
var attribute = new AppendUserModifiedHeaderAttribute(userIdParameter);
|
||||
|
||||
// Act
|
||||
attribute.OnActionExecuting(context);
|
||||
|
||||
// Assert
|
||||
context.HttpContext.Response.Headers.TryGetValue("X-Umb-User-Modified", out var headerValue);
|
||||
Assert.AreEqual("1", headerValue[0]);
|
||||
}
|
||||
|
||||
private static ActionExecutingContext CreateContext(
|
||||
string headerValue = null,
|
||||
KeyValuePair<string, object> actionArgument = default)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
if (!string.IsNullOrEmpty(headerValue))
|
||||
{
|
||||
httpContext.Response.Headers.Add("X-Umb-User-Modified", headerValue);
|
||||
}
|
||||
|
||||
var currentUserMock = new Mock<IUser>();
|
||||
currentUserMock
|
||||
.SetupGet(x => x.Id)
|
||||
.Returns(100);
|
||||
|
||||
var backofficeSecurityMock = new Mock<IBackOfficeSecurity>();
|
||||
backofficeSecurityMock
|
||||
.SetupGet(x => x.CurrentUser)
|
||||
.Returns(currentUserMock.Object);
|
||||
|
||||
var backofficeSecurityAccessorMock = new Mock<IBackOfficeSecurityAccessor>();
|
||||
backofficeSecurityAccessorMock
|
||||
.SetupGet(x => x.BackOfficeSecurity)
|
||||
.Returns(backofficeSecurityMock.Object);
|
||||
|
||||
var serviceProviderMock = new Mock<IServiceProvider>();
|
||||
serviceProviderMock
|
||||
.Setup(x => x.GetService(typeof(IBackOfficeSecurityAccessor)))
|
||||
.Returns(backofficeSecurityAccessorMock.Object);
|
||||
|
||||
httpContext.RequestServices = serviceProviderMock.Object;
|
||||
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||
|
||||
var context = new ActionExecutingContext(
|
||||
actionContext,
|
||||
new List<IFilterMetadata>(),
|
||||
new Dictionary<string, object>(),
|
||||
new Mock<Controller>().Object);
|
||||
|
||||
if (!EqualityComparer<KeyValuePair<string, object>>.Default.Equals(actionArgument, default))
|
||||
{
|
||||
context.ActionArguments.Add(actionArgument);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.PropertyEditors.Validation;
|
||||
using Umbraco.Cms.Web.BackOffice.PropertyEditors.Validation;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Filters;
|
||||
|
||||
[TestFixture]
|
||||
public class ContentModelValidatorTests
|
||||
{
|
||||
[Test]
|
||||
public void Test_Serializer()
|
||||
{
|
||||
var nestedLevel2 = new ComplexEditorValidationResult();
|
||||
var id1 = Guid.NewGuid();
|
||||
var addressInfoElementTypeResult = new ComplexEditorElementTypeValidationResult("addressInfo", id1);
|
||||
var cityPropertyTypeResult = new ComplexEditorPropertyTypeValidationResult("city");
|
||||
cityPropertyTypeResult.AddValidationResult(new ValidationResult("City is invalid"));
|
||||
cityPropertyTypeResult.AddValidationResult(new ValidationResult("City cannot be empty"));
|
||||
cityPropertyTypeResult.AddValidationResult(new ValidationResult("City is not in Australia", new[] { "country" }));
|
||||
cityPropertyTypeResult.AddValidationResult(new ValidationResult("Not a capital city", new[] { "capital" }));
|
||||
addressInfoElementTypeResult.ValidationResults.Add(cityPropertyTypeResult);
|
||||
nestedLevel2.ValidationResults.Add(addressInfoElementTypeResult);
|
||||
|
||||
var nestedLevel1 = new ComplexEditorValidationResult();
|
||||
var id2 = Guid.NewGuid();
|
||||
var addressBookElementTypeResult = new ComplexEditorElementTypeValidationResult("addressBook", id2);
|
||||
var addressesPropertyTypeResult = new ComplexEditorPropertyTypeValidationResult("addresses");
|
||||
addressesPropertyTypeResult.AddValidationResult(new ValidationResult("Must have at least 3 addresses", new[] { "counter" }));
|
||||
addressesPropertyTypeResult.AddValidationResult(nestedLevel2); // This is a nested result within the level 1
|
||||
addressBookElementTypeResult.ValidationResults.Add(addressesPropertyTypeResult);
|
||||
var bookNamePropertyTypeResult = new ComplexEditorPropertyTypeValidationResult("bookName");
|
||||
bookNamePropertyTypeResult.AddValidationResult(
|
||||
new ValidationResult("Invalid address book name", new[] { "book" }));
|
||||
addressBookElementTypeResult.ValidationResults.Add(bookNamePropertyTypeResult);
|
||||
nestedLevel1.ValidationResults.Add(addressBookElementTypeResult);
|
||||
|
||||
var id3 = Guid.NewGuid();
|
||||
var addressBookElementTypeResult2 = new ComplexEditorElementTypeValidationResult("addressBook", id3);
|
||||
var addressesPropertyTypeResult2 = new ComplexEditorPropertyTypeValidationResult("addresses");
|
||||
addressesPropertyTypeResult2.AddValidationResult(new ValidationResult("Must have at least 2 addresses", new[] { "counter" }));
|
||||
addressBookElementTypeResult2.ValidationResults.Add(addressesPropertyTypeResult);
|
||||
var bookNamePropertyTypeResult2 = new ComplexEditorPropertyTypeValidationResult("bookName");
|
||||
bookNamePropertyTypeResult2.AddValidationResult(new ValidationResult("Name is too long"));
|
||||
addressBookElementTypeResult2.ValidationResults.Add(bookNamePropertyTypeResult2);
|
||||
nestedLevel1.ValidationResults.Add(addressBookElementTypeResult2);
|
||||
|
||||
// books is the outer most validation result and doesn't have it's own direct ValidationResult errors
|
||||
var outerError = new ComplexEditorValidationResult();
|
||||
var id4 = Guid.NewGuid();
|
||||
var addressBookCollectionElementTypeResult =
|
||||
new ComplexEditorElementTypeValidationResult("addressBookCollection", id4);
|
||||
var booksPropertyTypeResult = new ComplexEditorPropertyTypeValidationResult("books");
|
||||
booksPropertyTypeResult.AddValidationResult(nestedLevel1); // books is the outer most validation result
|
||||
addressBookCollectionElementTypeResult.ValidationResults.Add(booksPropertyTypeResult);
|
||||
outerError.ValidationResults.Add(addressBookCollectionElementTypeResult);
|
||||
|
||||
var serialized = JsonConvert.SerializeObject(outerError, Formatting.Indented, new ValidationResultConverter());
|
||||
Console.WriteLine(serialized);
|
||||
|
||||
var jsonError = JsonConvert.DeserializeObject<JArray>(serialized);
|
||||
|
||||
Assert.IsNotNull(jsonError.SelectToken("$[0]"));
|
||||
Assert.AreEqual(id4.ToString(), jsonError.SelectToken("$[0].$id").Value<string>());
|
||||
Assert.AreEqual("addressBookCollection", jsonError.SelectToken("$[0].$elementTypeAlias").Value<string>());
|
||||
Assert.AreEqual(string.Empty, jsonError.SelectToken("$[0].ModelState['_Properties.books.invariant.null'][0]").Value<string>());
|
||||
|
||||
var error0 = jsonError.SelectToken("$[0].books") as JArray;
|
||||
Assert.IsNotNull(error0);
|
||||
Assert.AreEqual(id2.ToString(), error0.SelectToken("$[0].$id").Value<string>());
|
||||
Assert.AreEqual("addressBook", error0.SelectToken("$[0].$elementTypeAlias").Value<string>());
|
||||
Assert.IsNotNull(error0.SelectToken("$[0].ModelState"));
|
||||
Assert.AreEqual(string.Empty, error0.SelectToken("$[0].ModelState['_Properties.addresses.invariant.null'][0]").Value<string>());
|
||||
var error1 = error0.SelectToken("$[0].ModelState['_Properties.addresses.invariant.null.counter']") as JArray;
|
||||
Assert.IsNotNull(error1);
|
||||
Assert.AreEqual(1, error1.Count);
|
||||
var error2 = error0.SelectToken("$[0].ModelState['_Properties.bookName.invariant.null.book']") as JArray;
|
||||
Assert.IsNotNull(error2);
|
||||
Assert.AreEqual(1, error2.Count);
|
||||
|
||||
Assert.AreEqual(id3.ToString(), error0.SelectToken("$[1].$id").Value<string>());
|
||||
Assert.AreEqual("addressBook", error0.SelectToken("$[1].$elementTypeAlias").Value<string>());
|
||||
Assert.IsNotNull(error0.SelectToken("$[1].ModelState"));
|
||||
Assert.AreEqual(string.Empty, error0.SelectToken("$[1].ModelState['_Properties.addresses.invariant.null'][0]").Value<string>());
|
||||
var error6 = error0.SelectToken("$[1].ModelState['_Properties.addresses.invariant.null.counter']") as JArray;
|
||||
Assert.IsNotNull(error6);
|
||||
Assert.AreEqual(1, error6.Count);
|
||||
var error7 = error0.SelectToken("$[1].ModelState['_Properties.bookName.invariant.null']") as JArray;
|
||||
Assert.IsNotNull(error7);
|
||||
Assert.AreEqual(1, error7.Count);
|
||||
|
||||
Assert.IsNotNull(error0.SelectToken("$[0].addresses"));
|
||||
Assert.AreEqual(id1.ToString(), error0.SelectToken("$[0].addresses[0].$id").Value<string>());
|
||||
Assert.AreEqual("addressInfo", error0.SelectToken("$[0].addresses[0].$elementTypeAlias").Value<string>());
|
||||
Assert.IsNotNull(error0.SelectToken("$[0].addresses[0].ModelState"));
|
||||
var error3 =
|
||||
error0.SelectToken("$[0].addresses[0].ModelState['_Properties.city.invariant.null.country']") as JArray;
|
||||
Assert.IsNotNull(error3);
|
||||
Assert.AreEqual(1, error3.Count);
|
||||
var error4 =
|
||||
error0.SelectToken("$[0].addresses[0].ModelState['_Properties.city.invariant.null.capital']") as JArray;
|
||||
Assert.IsNotNull(error4);
|
||||
Assert.AreEqual(1, error4.Count);
|
||||
var error5 = error0.SelectToken("$[0].addresses[0].ModelState['_Properties.city.invariant.null']") as JArray;
|
||||
Assert.IsNotNull(error5);
|
||||
Assert.AreEqual(2, error5.Count);
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
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;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Filters;
|
||||
|
||||
[TestFixture]
|
||||
public class FilterAllowedOutgoingContentAttributeTests
|
||||
{
|
||||
[Test]
|
||||
public void GetValueFromResponse_Already_EnumerableContent()
|
||||
{
|
||||
var expected = new List<ContentItemBasic> { new() };
|
||||
|
||||
var att = new FilterAllowedOutgoingContentFilter(
|
||||
expected.GetType(),
|
||||
null,
|
||||
ActionBrowse.ActionLetter,
|
||||
Mock.Of<IUserService>(),
|
||||
Mock.Of<IEntityService>(),
|
||||
AppCaches.Disabled,
|
||||
Mock.Of<IBackOfficeSecurityAccessor>());
|
||||
|
||||
var result = att.GetValueFromResponse(new ObjectResult(expected));
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValueFromResponse_From_Property()
|
||||
{
|
||||
var expected = new List<ContentItemBasic> { new() };
|
||||
var container = new MyTestClass { MyList = expected };
|
||||
|
||||
var att = new FilterAllowedOutgoingContentFilter(
|
||||
expected.GetType(),
|
||||
nameof(MyTestClass.MyList),
|
||||
ActionBrowse.ActionLetter,
|
||||
Mock.Of<IUserService>(),
|
||||
Mock.Of<IEntityService>(),
|
||||
AppCaches.Disabled,
|
||||
Mock.Of<IBackOfficeSecurityAccessor>());
|
||||
|
||||
var result = att.GetValueFromResponse(new ObjectResult(container));
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetValueFromResponse_Returns_Null_Not_Found_Property()
|
||||
{
|
||||
var expected = new List<ContentItemBasic> { new() };
|
||||
var container = new MyTestClass { MyList = expected };
|
||||
|
||||
var att = new FilterAllowedOutgoingContentFilter(
|
||||
expected.GetType(),
|
||||
"DontFind",
|
||||
ActionBrowse.ActionLetter,
|
||||
Mock.Of<IUserService>(),
|
||||
Mock.Of<IEntityService>(),
|
||||
AppCaches.Disabled,
|
||||
Mock.Of<IBackOfficeSecurityAccessor>());
|
||||
|
||||
var actual = att.GetValueFromResponse(new ObjectResult(container));
|
||||
|
||||
Assert.IsNull(actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Filter_On_Start_Node()
|
||||
{
|
||||
var user = CreateUser(9, 5);
|
||||
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 == 5 && entity.Path == "-1,5") });
|
||||
var entityService = entityServiceMock.Object;
|
||||
|
||||
var list = new List<ContentItemBasic>();
|
||||
var att = new FilterAllowedOutgoingContentFilter(
|
||||
list.GetType(),
|
||||
null,
|
||||
ActionBrowse.ActionLetter,
|
||||
userService,
|
||||
entityService,
|
||||
AppCaches.Disabled,
|
||||
Mock.Of<IBackOfficeSecurityAccessor>());
|
||||
|
||||
var path = string.Empty;
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
if (i > 0 && path.EndsWith(",") == false)
|
||||
{
|
||||
path += ",";
|
||||
}
|
||||
|
||||
path += i.ToInvariantString();
|
||||
list.Add(new ContentItemBasic { Id = i, Name = "Test" + i, ParentId = i, Path = path });
|
||||
}
|
||||
|
||||
att.FilterBasedOnStartNode(list, user);
|
||||
|
||||
Assert.AreEqual(5, list.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Filter_On_Permissions()
|
||||
{
|
||||
var list = new List<ContentItemBasic>();
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
list.Add(new ContentItemBasic { Id = i, Name = "Test" + i, ParentId = -1 });
|
||||
}
|
||||
|
||||
var ids = list.Select(x => (int)x.Id).ToArray();
|
||||
|
||||
var user = CreateUser(9, 0);
|
||||
|
||||
var userServiceMock = new Mock<IUserService>();
|
||||
|
||||
// We're only assigning 3 nodes browse permissions so that is what we expect as a result
|
||||
var permissions = new EntityPermissionCollection
|
||||
{
|
||||
new(9876, 1, new[] { ActionBrowse.ActionLetter.ToString() }),
|
||||
new(9876, 2, new[] { ActionBrowse.ActionLetter.ToString() }),
|
||||
new(9876, 3, new[] { ActionBrowse.ActionLetter.ToString() }),
|
||||
new(9876, 4, new[] { ActionUpdate.ActionLetter.ToString() }),
|
||||
};
|
||||
userServiceMock.Setup(x => x.GetPermissions(user, ids)).Returns(permissions);
|
||||
var userService = userServiceMock.Object;
|
||||
|
||||
var att = new FilterAllowedOutgoingContentFilter(
|
||||
list.GetType(),
|
||||
null,
|
||||
ActionBrowse.ActionLetter,
|
||||
userService,
|
||||
Mock.Of<IEntityService>(),
|
||||
AppCaches.Disabled,
|
||||
Mock.Of<IBackOfficeSecurityAccessor>());
|
||||
att.FilterBasedOnPermissions(list, user);
|
||||
|
||||
Assert.AreEqual(3, list.Count);
|
||||
Assert.AreEqual(1, list.ElementAt(0).Id);
|
||||
Assert.AreEqual(2, list.ElementAt(1).Id);
|
||||
Assert.AreEqual(3, list.ElementAt(2).Id);
|
||||
}
|
||||
|
||||
private IUser CreateUser(int id = 0, int? startContentId = null) =>
|
||||
new UserBuilder()
|
||||
.WithId(id)
|
||||
.WithStartContentIds(startContentId.HasValue ? new[] { startContentId.Value } : new int[0])
|
||||
.Build();
|
||||
|
||||
private class MyTestClass
|
||||
{
|
||||
public IEnumerable<ContentItemBasic> MyList { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Web.BackOffice.Filters;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Filters;
|
||||
|
||||
[TestFixture]
|
||||
public class ValidationFilterAttributeTests
|
||||
{
|
||||
[Test]
|
||||
public void Does_Not_Set_Result_When_No_Errors_In_Model_State()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext();
|
||||
var attribute = new ValidationFilterAttribute();
|
||||
|
||||
// Act
|
||||
attribute.OnActionExecuting(context);
|
||||
|
||||
// Assert
|
||||
Assert.IsNull(context.Result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Returns_Bad_Request_When_Errors_In_Model_State()
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(true);
|
||||
var attribute = new ValidationFilterAttribute();
|
||||
|
||||
// Act
|
||||
attribute.OnActionExecuting(context);
|
||||
|
||||
// Assert
|
||||
var typedResult = context.Result as BadRequestObjectResult;
|
||||
Assert.IsNotNull(typedResult);
|
||||
}
|
||||
|
||||
private static ActionExecutingContext CreateContext(bool withError = false)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
|
||||
var modelState = new ModelStateDictionary();
|
||||
if (withError)
|
||||
{
|
||||
modelState.AddModelError(string.Empty, "Error");
|
||||
}
|
||||
|
||||
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor(), modelState);
|
||||
|
||||
return new ActionExecutingContext(
|
||||
actionContext,
|
||||
new List<IFilterMetadata>(),
|
||||
new Dictionary<string, object>(),
|
||||
new Mock<Controller>().Object);
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
using Umbraco.Cms.Web.BackOffice.Security;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security;
|
||||
|
||||
[TestFixture]
|
||||
public class BackOfficeCookieManagerTests
|
||||
{
|
||||
[Test]
|
||||
public void ShouldAuthenticateRequest_When_Not_Configured()
|
||||
{
|
||||
var globalSettings = new GlobalSettings();
|
||||
var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions();
|
||||
|
||||
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Install);
|
||||
var mgr = new BackOfficeCookieManager(
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
runtime,
|
||||
new UmbracoRequestPaths(Options.Create(globalSettings), TestHelper.GetHostingEnvironment(), Options.Create(umbracoRequestPathsOptions)),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/umbraco");
|
||||
|
||||
Assert.IsFalse(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldAuthenticateRequest_When_Configured()
|
||||
{
|
||||
var globalSettings = new GlobalSettings();
|
||||
var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions();
|
||||
|
||||
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run);
|
||||
var mgr = new BackOfficeCookieManager(
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x =>
|
||||
x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco"),
|
||||
Options.Create(umbracoRequestPathsOptions)),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/umbraco");
|
||||
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldAuthenticateRequest_Is_Back_Office()
|
||||
{
|
||||
var globalSettings = new GlobalSettings();
|
||||
var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions();
|
||||
|
||||
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run);
|
||||
|
||||
GenerateAuthPaths(out var remainingTimeoutSecondsPath, out var isAuthPath);
|
||||
|
||||
var mgr = new BackOfficeCookieManager(
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x =>
|
||||
x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" &&
|
||||
x.ToAbsolute(Constants.SystemDirectories.Install) == "/install"),
|
||||
Options.Create(umbracoRequestPathsOptions)),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest(remainingTimeoutSecondsPath);
|
||||
Assert.IsTrue(result);
|
||||
|
||||
result = mgr.ShouldAuthenticateRequest(isAuthPath);
|
||||
Assert.IsTrue(result);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ShouldAuthenticateRequest_Not_Back_Office()
|
||||
{
|
||||
var globalSettings = new GlobalSettings();
|
||||
var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions();
|
||||
|
||||
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run);
|
||||
|
||||
var mgr = new BackOfficeCookieManager(
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x =>
|
||||
x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" &&
|
||||
x.ToAbsolute(Constants.SystemDirectories.Install) == "/install"),
|
||||
Options.Create(umbracoRequestPathsOptions)),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/notbackoffice");
|
||||
Assert.IsFalse(result);
|
||||
result = mgr.ShouldAuthenticateRequest("/umbraco/api/notbackoffice");
|
||||
Assert.IsFalse(result);
|
||||
result = mgr.ShouldAuthenticateRequest("/umbraco/surface/notbackoffice");
|
||||
Assert.IsFalse(result);
|
||||
}
|
||||
|
||||
private void GenerateAuthPaths(out string remainingTimeoutSecondsPath, out string isAuthPath)
|
||||
{
|
||||
var controllerName = ControllerExtensions.GetControllerName<AuthenticationController>();
|
||||
|
||||
// this path is not a back office request even though it's in the same controller - it's a 'special' endpoint
|
||||
var rPath = remainingTimeoutSecondsPath =
|
||||
$"/umbraco/{Constants.Web.Mvc.BackOfficePathSegment}/{Constants.Web.Mvc.BackOfficeApiArea}/{controllerName}/{nameof(AuthenticationController.GetRemainingTimeoutSeconds)}"
|
||||
.ToLower();
|
||||
|
||||
// this is on the same controller but is considered a back office request
|
||||
var aPath = isAuthPath =
|
||||
$"/umbraco/{Constants.Web.Mvc.BackOfficePathSegment}/{Constants.Web.Mvc.BackOfficeApiArea}/{controllerName}/{nameof(AuthenticationController.IsAuthenticated)}"
|
||||
.ToLower();
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Infrastructure.WebAssets;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Common.AngularIntegration;
|
||||
|
||||
[TestFixture]
|
||||
public class ServerVariablesParserTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Parse()
|
||||
{
|
||||
var parser = new ServerVariablesParser(Mock.Of<IEventAggregator>());
|
||||
|
||||
var d = new Dictionary<string, object>
|
||||
{
|
||||
{ "test1", "Test 1" },
|
||||
{ "test2", "Test 2" },
|
||||
{ "test3", "Test 3" },
|
||||
{ "test4", "Test 4" },
|
||||
{ "test5", "Test 5" },
|
||||
};
|
||||
|
||||
var output = (await parser.ParseAsync(d)).StripWhitespace();
|
||||
|
||||
Assert.IsTrue(output.Contains(@"Umbraco.Sys.ServerVariables = {
|
||||
""test1"": ""Test 1"",
|
||||
""test2"": ""Test 2"",
|
||||
""test3"": ""Test 3"",
|
||||
""test4"": ""Test 4"",
|
||||
""test5"": ""Test 5""
|
||||
} ;".StripWhitespace()));
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,10 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Controllers.Security;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Tests.UnitTests.AutoFixture;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
using Umbraco.Cms.Web.BackOffice.Install;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Common;
|
||||
|
||||
@@ -37,45 +36,7 @@ internal class FileNameTests
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public async Task InstallViewExists(
|
||||
[Frozen] IHostingEnvironment hostingEnvironment,
|
||||
InstallController sut)
|
||||
{
|
||||
Mock.Get(hostingEnvironment).Setup(x => x.ToAbsolute(It.IsAny<string>())).Returns("http://localhost/");
|
||||
var viewResult = await sut.Index() as ViewResult;
|
||||
var fileName = GetViewName(viewResult, Path.DirectorySeparatorChar.ToString());
|
||||
|
||||
var views = GetUiFiles(new[] { "umbraco", "UmbracoInstall" });
|
||||
Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public void PreviewViewExists(PreviewController sut)
|
||||
{
|
||||
var viewResult = sut.Index() as ViewResult;
|
||||
var fileName = GetViewName(viewResult);
|
||||
|
||||
var views = GetUiFiles(new[] { "umbraco", "UmbracoBackOffice" });
|
||||
|
||||
Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public async Task LoginViewExists(BackOfficeController sut)
|
||||
{
|
||||
var viewResult = await sut.Login() as ViewResult;
|
||||
var fileName = GetViewName(viewResult);
|
||||
|
||||
var views = GetUiFiles(new[] { "umbraco", "UmbracoLogin" });
|
||||
|
||||
Assert.True(views.Contains(fileName), $"Expected {fileName} to exist, but it didn't");
|
||||
}
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public void BackOfficeDefaultExists(BackOfficeController sut)
|
||||
public void BackOfficeDefaultExists(BackOfficeDefaultController sut)
|
||||
{
|
||||
var viewResult = sut.DefaultView();
|
||||
var fileName = GetViewName(viewResult);
|
||||
|
||||
@@ -7,12 +7,12 @@ using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Controllers.Security;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
using Umbraco.Cms.Web.BackOffice.Routing;
|
||||
using Umbraco.Cms.Web.Common.Attributes;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
@@ -47,11 +47,11 @@ public class BackOfficeAreaRoutesTests
|
||||
|
||||
Assert.AreEqual(1, endpoints.DataSources.Count);
|
||||
var route = endpoints.DataSources.First();
|
||||
Assert.AreEqual(4, route.Endpoints.Count);
|
||||
Assert.AreEqual(3, route.Endpoints.Count);
|
||||
|
||||
AssertMinimalBackOfficeRoutes(route);
|
||||
|
||||
var endpoint4 = (RouteEndpoint)route.Endpoints[3];
|
||||
var endpoint4 = (RouteEndpoint)route.Endpoints[2];
|
||||
var apiControllerName = ControllerExtensions.GetControllerName<Testing1Controller>();
|
||||
Assert.AreEqual(
|
||||
$"umbraco/backoffice/api/{apiControllerName.ToLowerInvariant()}/{{action}}/{{id?}}",
|
||||
@@ -65,26 +65,8 @@ public class BackOfficeAreaRoutesTests
|
||||
{
|
||||
var endpoint1 = (RouteEndpoint)route.Endpoints[0];
|
||||
Assert.AreEqual("umbraco/{action}/{id?}", endpoint1.RoutePattern.RawText);
|
||||
Assert.AreEqual(Constants.Web.Mvc.BackOfficeArea, endpoint1.RoutePattern.Defaults[AreaToken]);
|
||||
Assert.AreEqual("Default", endpoint1.RoutePattern.Defaults[ActionToken]);
|
||||
Assert.AreEqual(
|
||||
ControllerExtensions.GetControllerName<BackOfficeController>(),
|
||||
endpoint1.RoutePattern.Defaults[ControllerToken]);
|
||||
Assert.AreEqual(
|
||||
endpoint1.RoutePattern.Defaults[AreaToken],
|
||||
typeof(BackOfficeController).GetCustomAttribute<AreaAttribute>(false).RouteValue);
|
||||
|
||||
var endpoint2 = (RouteEndpoint)route.Endpoints[1];
|
||||
var controllerName = ControllerExtensions.GetControllerName<AuthenticationController>();
|
||||
Assert.AreEqual(
|
||||
$"umbraco/backoffice/{Constants.Web.Mvc.BackOfficeApiArea.ToLowerInvariant()}/{controllerName.ToLowerInvariant()}/{{action}}/{{id?}}",
|
||||
endpoint2.RoutePattern.RawText);
|
||||
Assert.AreEqual(Constants.Web.Mvc.BackOfficeApiArea, endpoint2.RoutePattern.Defaults[AreaToken]);
|
||||
Assert.IsFalse(endpoint2.RoutePattern.Defaults.ContainsKey(ActionToken));
|
||||
Assert.AreEqual(controllerName, endpoint2.RoutePattern.Defaults[ControllerToken]);
|
||||
Assert.AreEqual(
|
||||
endpoint1.RoutePattern.Defaults[AreaToken],
|
||||
typeof(BackOfficeController).GetCustomAttribute<AreaAttribute>(false).RouteValue);
|
||||
Assert.AreEqual("Index", endpoint1.RoutePattern.Defaults[ActionToken]);
|
||||
Assert.AreEqual(ControllerExtensions.GetControllerName<BackOfficeDefaultController>(), endpoint1.RoutePattern.Defaults[ControllerToken]);
|
||||
}
|
||||
|
||||
private BackOfficeAreaRoutes GetBackOfficeAreaRoutes(RuntimeLevel level)
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Install;
|
||||
using Umbraco.Extensions;
|
||||
using static Umbraco.Cms.Core.Constants.Web.Routing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.Common.Routing;
|
||||
|
||||
[TestFixture]
|
||||
public class InstallAreaRoutesTests
|
||||
{
|
||||
[TestCase(RuntimeLevel.BootFailed)]
|
||||
[TestCase(RuntimeLevel.Unknown)]
|
||||
[TestCase(RuntimeLevel.Boot)]
|
||||
public void RuntimeState_No_Routes(RuntimeLevel level)
|
||||
{
|
||||
var routes = GetInstallAreaRoutes(level);
|
||||
var endpoints = new TestRouteBuilder();
|
||||
routes.CreateRoutes(endpoints);
|
||||
|
||||
Assert.AreEqual(0, endpoints.DataSources.Count);
|
||||
}
|
||||
|
||||
[TestCase(RuntimeLevel.Install)]
|
||||
[TestCase(RuntimeLevel.Upgrade)]
|
||||
public void RuntimeState_Install(RuntimeLevel level)
|
||||
{
|
||||
var routes = GetInstallAreaRoutes(level);
|
||||
var endpoints = new TestRouteBuilder();
|
||||
routes.CreateRoutes(endpoints);
|
||||
|
||||
Assert.AreEqual(1, endpoints.DataSources.Count);
|
||||
var route = endpoints.DataSources.First();
|
||||
Assert.AreEqual(2, route.Endpoints.Count);
|
||||
|
||||
var endpoint1 = (RouteEndpoint)route.Endpoints[0];
|
||||
Assert.AreEqual("install/api/{action}/{id?}", endpoint1.RoutePattern.RawText);
|
||||
Assert.AreEqual(Constants.Web.Mvc.InstallArea, endpoint1.RoutePattern.Defaults[AreaToken]);
|
||||
Assert.AreEqual("Index", endpoint1.RoutePattern.Defaults[ActionToken]);
|
||||
Assert.AreEqual(
|
||||
ControllerExtensions.GetControllerName<InstallApiController>(),
|
||||
endpoint1.RoutePattern.Defaults[ControllerToken]);
|
||||
Assert.AreEqual(
|
||||
endpoint1.RoutePattern.Defaults[AreaToken],
|
||||
typeof(InstallApiController).GetCustomAttribute<AreaAttribute>(false).RouteValue);
|
||||
|
||||
var endpoint2 = (RouteEndpoint)route.Endpoints[1];
|
||||
Assert.AreEqual("install/{action}/{id?}", endpoint2.RoutePattern.RawText);
|
||||
Assert.AreEqual(Constants.Web.Mvc.InstallArea, endpoint2.RoutePattern.Defaults[AreaToken]);
|
||||
Assert.AreEqual("Index", endpoint2.RoutePattern.Defaults[ActionToken]);
|
||||
Assert.AreEqual(
|
||||
ControllerExtensions.GetControllerName<InstallController>(),
|
||||
endpoint2.RoutePattern.Defaults[ControllerToken]);
|
||||
Assert.AreEqual(
|
||||
endpoint2.RoutePattern.Defaults[AreaToken],
|
||||
typeof(InstallController).GetCustomAttribute<AreaAttribute>(false).RouteValue);
|
||||
|
||||
var dataSource = endpoints.DataSources.Last();
|
||||
Assert.AreEqual(2, dataSource.Endpoints.Count);
|
||||
|
||||
Assert.AreEqual("Route: install/api/{action}/{id?}", dataSource.Endpoints[0].ToString());
|
||||
Assert.AreEqual("Route: install/{action}/{id?}", dataSource.Endpoints[1].ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RuntimeState_Run()
|
||||
{
|
||||
var routes = GetInstallAreaRoutes(RuntimeLevel.Run);
|
||||
var endpoints = new TestRouteBuilder();
|
||||
routes.CreateRoutes(endpoints);
|
||||
|
||||
Assert.AreEqual(1, endpoints.DataSources.Count);
|
||||
var route = endpoints.DataSources.First();
|
||||
Assert.AreEqual(2, route.Endpoints.Count);
|
||||
|
||||
var endpoint = (RouteEndpoint)route.Endpoints[0];
|
||||
Assert.AreEqual("install/api/{action}/{id?}", endpoint.RoutePattern.RawText);
|
||||
|
||||
endpoint = (RouteEndpoint)route.Endpoints[1];
|
||||
Assert.AreEqual("install/{action}/{id?}", endpoint.RoutePattern.RawText);
|
||||
}
|
||||
|
||||
private InstallAreaRoutes GetInstallAreaRoutes(RuntimeLevel level) =>
|
||||
new(
|
||||
Mock.Of<IRuntimeState>(x => x.Level == level),
|
||||
Mock.Of<IHostingEnvironment>(x =>
|
||||
x.ToAbsolute(It.IsAny<string>()) == "/install" && x.ApplicationVirtualPath == string.Empty),
|
||||
Mock.Of<LinkGenerator>());
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
// Copyright (c) Umbraco.
|
||||
// See LICENSE for more details.
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Controllers.Preview;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Hosting;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
using Umbraco.Cms.Web.BackOffice.Routing;
|
||||
using Umbraco.Extensions;
|
||||
using static Umbraco.Cms.Core.Constants.Web.Routing;
|
||||
|
||||
@@ -42,7 +41,7 @@ public class PreviewRoutesTests
|
||||
var endpoints = new TestRouteBuilder();
|
||||
routes.CreateRoutes(endpoints);
|
||||
|
||||
Assert.AreEqual(2, endpoints.DataSources.Count);
|
||||
Assert.AreEqual(1, endpoints.DataSources.Count);
|
||||
var route = endpoints.DataSources.First();
|
||||
Assert.AreEqual(2, route.Endpoints.Count);
|
||||
|
||||
@@ -50,18 +49,6 @@ public class PreviewRoutesTests
|
||||
Assert.AreEqual($"{routes.GetPreviewHubRoute()}/negotiate", endpoint0.RoutePattern.RawText);
|
||||
var endpoint1 = (RouteEndpoint)route.Endpoints[1];
|
||||
Assert.AreEqual($"{routes.GetPreviewHubRoute()}", endpoint1.RoutePattern.RawText);
|
||||
|
||||
var endpoint3 = (RouteEndpoint)endpoints.DataSources.Last().Endpoints[0];
|
||||
var previewControllerName = ControllerExtensions.GetControllerName<PreviewController>();
|
||||
Assert.AreEqual(
|
||||
$"umbraco/{previewControllerName.ToLowerInvariant()}/{{action}}/{{id?}}",
|
||||
endpoint3.RoutePattern.RawText);
|
||||
Assert.AreEqual(Constants.Web.Mvc.BackOfficeArea, endpoint3.RoutePattern.Defaults["area"]);
|
||||
Assert.AreEqual("Index", endpoint3.RoutePattern.Defaults[ActionToken]);
|
||||
Assert.AreEqual(previewControllerName, endpoint3.RoutePattern.Defaults[ControllerToken]);
|
||||
Assert.AreEqual(
|
||||
endpoint3.RoutePattern.Defaults["area"],
|
||||
typeof(PreviewController).GetCustomAttribute<AreaAttribute>(false).RouteValue);
|
||||
}
|
||||
|
||||
private PreviewRoutes GetRoutes(RuntimeLevel level)
|
||||
|
||||
Reference in New Issue
Block a user