Adhered to linting rules for authorization policy handlers, requirements and tests.

This commit is contained in:
Andy Butland
2020-12-06 09:13:29 +01:00
parent 05dc597fc2
commit 61cbb84dd3
37 changed files with 697 additions and 461 deletions

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -32,8 +35,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Missing_QueryString_Value_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringName: "xxx");
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
AdminUsersHandler sut = CreateHandler(queryStringName: "xxx");
await sut.HandleAsync(authHandlerContext);
@@ -43,8 +46,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Non_Integer_QueryString_Value_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: "xxx");
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
AdminUsersHandler sut = CreateHandler(queryStringValue: "xxx");
await sut.HandleAsync(authHandlerContext);
@@ -54,8 +57,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Editing_Single_Admin_User_By_Admin_User_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: Admin2UserId.ToString(), editingWithAdmin: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString(), editingWithAdmin: true);
await sut.HandleAsync(authHandlerContext);
@@ -65,8 +68,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Editing_Single_Admin_User_By_Non_Admin_User_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: Admin2UserId.ToString());
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
AdminUsersHandler sut = CreateHandler(queryStringValue: Admin2UserId.ToString());
await sut.HandleAsync(authHandlerContext);
@@ -76,8 +79,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Editing_Single_Non_Admin_User_By_Non_Admin_User_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: NonAdmin2UserId.ToString());
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
AdminUsersHandler sut = CreateHandler(queryStringValue: NonAdmin2UserId.ToString());
await sut.HandleAsync(authHandlerContext);
@@ -87,8 +90,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Editing_Multiple_Users_Including_Admins_By_Admin_User_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(queryStringName: MultipleUserEditQueryStringName);
var sut = CreateHandler(queryStringName: MultipleUserEditQueryStringName, queryStringValue: $"{Admin2UserId},{NonAdmin2UserId}", editingWithAdmin: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(queryStringName: MultipleUserEditQueryStringName);
AdminUsersHandler sut = CreateHandler(queryStringName: MultipleUserEditQueryStringName, queryStringValue: $"{Admin2UserId},{NonAdmin2UserId}", editingWithAdmin: true);
await sut.HandleAsync(authHandlerContext);
@@ -98,8 +101,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Editing_Multiple_Users_Including_Admins_By_Non_Admin_User_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(queryStringName: MultipleUserEditQueryStringName);
var sut = CreateHandler(queryStringName: MultipleUserEditQueryStringName, queryStringValue: $"{Admin2UserId},{NonAdmin2UserId}");
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(queryStringName: MultipleUserEditQueryStringName);
AdminUsersHandler sut = CreateHandler(queryStringName: MultipleUserEditQueryStringName, queryStringValue: $"{Admin2UserId},{NonAdmin2UserId}");
await sut.HandleAsync(authHandlerContext);
@@ -109,8 +112,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Editing_Multiple_Users_Not_Including_Admins_By_Non_Admin_User_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(queryStringName: MultipleUserEditQueryStringName);
var sut = CreateHandler(queryStringName: MultipleUserEditQueryStringName, queryStringValue: $"{NonAdmin2UserId},{NonAdmin3UserId}");
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(queryStringName: MultipleUserEditQueryStringName);
AdminUsersHandler sut = CreateHandler(queryStringName: MultipleUserEditQueryStringName, queryStringValue: $"{NonAdmin2UserId},{NonAdmin3UserId}");
await sut.HandleAsync(authHandlerContext);
@@ -121,15 +124,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new AdminUsersRequirement(queryStringName);
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object 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();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringName, queryStringValue);
CreateMockUserServiceAndSecurityAccessor(editingWithAdmin, out Mock<IUserService> mockUserService, out Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor);
UserEditorAuthorizationHelper userEditorAuthorizationHelper = CreateUserEditorAuthorizationHelper();
return new AdminUsersHandler(mockHttpContextAccessor.Object, mockUserService.Object, mockBackOfficeSecurityAccessor.Object, userEditorAuthorizationHelper);
}
@@ -152,11 +155,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
mockUserService = new Mock<IUserService>();
var globalSettings = new GlobalSettings();
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);
User adminUser1 = CreateUser(Admin1UserId, mockUserService, true);
User adminUser2 = CreateUser(Admin2UserId, mockUserService, true);
User nonAdminUser1 = CreateUser(NonAdmin1UserId, mockUserService);
User nonAdminUser2 = CreateUser(NonAdmin2UserId, mockUserService);
User 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.
@@ -175,7 +178,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static User CreateUser(int id, Mock<IUserService> mockUserService, bool isAdmin = false)
{
var user = new UserBuilder()
User user = new UserBuilder()
.WithId(id)
.AddUserGroup()
.WithAlias(isAdmin ? Constants.Security.AdminGroupAlias : Constants.Security.EditorGroupAlias)

View File

@@ -1,3 +1,6 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
@@ -17,8 +20,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Runtime_State_Install_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(runtimeLevel: RuntimeLevel.Install);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
BackOfficeHandler sut = CreateHandler(runtimeLevel: RuntimeLevel.Install);
await sut.HandleAsync(authHandlerContext);
@@ -28,8 +31,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Runtime_State_Upgrade_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(runtimeLevel: RuntimeLevel.Upgrade);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
BackOfficeHandler sut = CreateHandler(runtimeLevel: RuntimeLevel.Upgrade);
await sut.HandleAsync(authHandlerContext);
@@ -39,8 +42,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Unauthenticated_User_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler();
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
BackOfficeHandler sut = CreateHandler();
await sut.HandleAsync(authHandlerContext);
@@ -50,8 +53,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Authenticated_User_Is_Not_Authorized_When_Not_Approved_And_Approval_Required()
{
var authHandlerContext = CreateAuthorizationHandlerContext(requireApproval: true);
var sut = CreateHandler(currentUserIsAuthenticated: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(requireApproval: true);
BackOfficeHandler sut = CreateHandler(currentUserIsAuthenticated: true);
await sut.HandleAsync(authHandlerContext);
@@ -61,8 +64,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Authenticated_User_Is_Authorized_When_Not_Approved_And_Approval_Not_Required()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(currentUserIsAuthenticated: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
BackOfficeHandler sut = CreateHandler(currentUserIsAuthenticated: true);
await sut.HandleAsync(authHandlerContext);
@@ -72,8 +75,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Authenticated_User_Is_Authorized_When_Approved_And_Approval_Required()
{
var authHandlerContext = CreateAuthorizationHandlerContext(requireApproval: true);
var sut = CreateHandler(currentUserIsAuthenticated: true, currentUserIsApproved: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(requireApproval: true);
BackOfficeHandler sut = CreateHandler(currentUserIsAuthenticated: true, currentUserIsApproved: true);
await sut.HandleAsync(authHandlerContext);
@@ -84,20 +87,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new BackOfficeRequirement(requireApproval);
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object 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);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(currentUserIsAuthenticated, currentUserIsApproved);
Mock<IRuntimeState> mockRuntimeState = CreateMockRuntimeState(runtimeLevel);
return new BackOfficeHandler(mockBackOfficeSecurityAccessor.Object, mockRuntimeState.Object);
}
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(bool currentUserIsAuthenticated, bool currentUserIsApproved)
{
var user = new UserBuilder()
global::Umbraco.Core.Models.Membership.User user = new UserBuilder()
.WithIsApproved(currentUserIsApproved)
.Build();
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -25,13 +28,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_With_Access_To_All_Descendent_Nodes_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockUserService = CreateMockUserService(NodeId, new Dictionary<int, string[]>
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IUserService> mockUserService = CreateMockUserService(NodeId, new Dictionary<int, string[]>
{
{ DescendentNodeId1, new string[] { "A" } },
{ DescendentNodeId2, new string[] { "A" } }
});
var sut = CreateHandler(mockUserService.Object, NodeId);
ContentPermissionsPublishBranchHandler sut = CreateHandler(mockUserService.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -42,13 +45,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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[]>
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IUserService> mockUserService = CreateMockUserService(NodeId, new Dictionary<int, string[]>
{
{ DescendentNodeId1, new string[] { "A" } },
{ DescendentNodeId2, new string[] { "B" } }
});
var sut = CreateHandler(mockUserService.Object, NodeId);
ContentPermissionsPublishBranchHandler sut = CreateHandler(mockUserService.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -59,13 +62,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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[]>
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IUserService> mockUserService = CreateMockUserService(NodeId, new Dictionary<int, string[]>
{
{ DescendentNodeId1, new string[] { "B" } },
{ DescendentNodeId2, new string[] { "A" } }
});
var sut = CreateHandler(mockUserService.Object, NodeId);
ContentPermissionsPublishBranchHandler sut = CreateHandler(mockUserService.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -77,7 +80,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new ContentPermissionsPublishBranchRequirement('A');
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = CreateContent(NodeId);
IContent resource = CreateContent(NodeId);
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
}
@@ -97,9 +100,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private ContentPermissionsPublishBranchHandler CreateHandler(IUserService userService, int nodeId)
{
var mockEntityService = CreateMockEntityService();
var contentPermissions = CreateContentPermissions(mockEntityService.Object, userService, nodeId);
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
Mock<IEntityService> mockEntityService = CreateMockEntityService();
ContentPermissions contentPermissions = CreateContentPermissions(mockEntityService.Object, userService, nodeId);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
return new ContentPermissionsPublishBranchHandler(mockEntityService.Object, contentPermissions, mockBackOfficeSecurityAccessor.Object);
}
@@ -129,13 +132,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static IContent CreateContent(int nodeId)
{
var contentType = ContentTypeBuilder.CreateBasicContentType();
ContentType contentType = ContentTypeBuilder.CreateBasicContentType();
return ContentBuilder.CreateBasicContent(contentType, nodeId);
}
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor()
{
var user = CreateUser();
User user = CreateUser();
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
@@ -143,10 +146,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser()
{
return new UserBuilder()
private static User CreateUser() =>
new UserBuilder()
.Build();
}
}
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
@@ -21,15 +24,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
private const string QueryStringName = "id";
private const int NodeId = 1000;
private static readonly Guid NodeGuid = Guid.NewGuid();
private static readonly Udi NodeUdi = UdiParser.Parse($"umb://document/{NodeGuid.ToString().ToLowerInvariant().Replace("-", string.Empty)}");
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 string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor();
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -39,9 +42,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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 string[] { "B" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor();
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "B" });
await sut.HandleAsync(authHandlerContext);
@@ -52,9 +55,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Id_Missing_From_Requirement_And_QueryString_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringName: "xxx");
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringName: "xxx");
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -64,9 +67,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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 string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -77,9 +80,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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 string[] { "B" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "B" });
await sut.HandleAsync(authHandlerContext);
@@ -90,9 +93,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeUdi.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -103,9 +106,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeUdi.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "B" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "B" });
await sut.HandleAsync(authHandlerContext);
@@ -116,9 +119,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeGuid.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -129,9 +132,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeGuid.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "B" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "B" });
await sut.HandleAsync(authHandlerContext);
@@ -142,9 +145,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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 string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: "invalid");
ContentPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -154,11 +157,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static AuthorizationHandlerContext CreateAuthorizationHandlerContext(int? nodeId = null)
{
const char Permission = 'A';
var requirement = nodeId.HasValue
ContentPermissionsQueryStringRequirement requirement = nodeId.HasValue
? new ContentPermissionsQueryStringRequirement(nodeId.Value, Permission)
: new ContentPermissionsQueryStringRequirement(Permission, QueryStringName);
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object resource = new object();
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
}
@@ -180,9 +183,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private ContentPermissionsQueryStringHandler CreateHandler(IHttpContextAccessor httpContextAccessor, int nodeId, string[] permissionsForPath)
{
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
var mockEntityService = CreateMockEntityService();
var contentPermissions = CreateContentPermissions(mockEntityService.Object, nodeId, permissionsForPath);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
Mock<IEntityService> mockEntityService = CreateMockEntityService();
ContentPermissions contentPermissions = CreateContentPermissions(mockEntityService.Object, nodeId, permissionsForPath);
return new ContentPermissionsQueryStringHandler(mockBackOfficeSecurityAccessor.Object, httpContextAccessor, mockEntityService.Object, contentPermissions);
}
@@ -190,17 +193,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var mockEntityService = new Mock<IEntityService>();
mockEntityService
.Setup(x => x.GetId(It.Is<Udi>(y => y == NodeUdi)))
.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 == NodeGuid), It.Is<UmbracoObjectTypes>(y => y == UmbracoObjectTypes.Document)))
.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();
User user = CreateUser();
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
@@ -208,11 +211,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser()
{
return new UserBuilder()
private static User CreateUser() =>
new UserBuilder()
.Build();
}
private static ContentPermissions CreateContentPermissions(IEntityService entityService, int nodeId, string[] permissionsForPath)
{
@@ -232,13 +233,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static IContent CreateContent(int nodeId)
{
var contentType = ContentTypeBuilder.CreateBasicContentType();
ContentType contentType = ContentTypeBuilder.CreateBasicContentType();
return ContentBuilder.CreateBasicContent(contentType, nodeId);
}
private static void AssertContentCached(Mock<IHttpContextAccessor> mockHttpContextAccessor)
{
private static void AssertContentCached(Mock<IHttpContextAccessor> mockHttpContextAccessor) =>
Assert.AreEqual(NodeId, ((IContent)mockHttpContextAccessor.Object.HttpContext.Items[typeof(IContent).ToString()]).Id);
}
}
}

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -21,8 +24,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Node_Id_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
var sut = CreateHandler(NodeId, new string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
ContentPermissionsResourceHandler sut = CreateHandler(NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -32,8 +35,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Content_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
var sut = CreateHandler(NodeId, new string[] { "A" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
ContentPermissionsResourceHandler sut = CreateHandler(NodeId, new string[] { "A" });
await sut.HandleAsync(authHandlerContext);
@@ -43,8 +46,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Node_Id_Withou_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
var sut = CreateHandler(NodeId, new string[] { "B" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
ContentPermissionsResourceHandler sut = CreateHandler(NodeId, new string[] { "B" });
await sut.HandleAsync(authHandlerContext);
@@ -54,8 +57,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Content_Without_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
var sut = CreateHandler(NodeId, new string[] { "B" });
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
ContentPermissionsResourceHandler sut = CreateHandler(NodeId, new string[] { "B" });
await sut.HandleAsync(authHandlerContext);
@@ -66,9 +69,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
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
IContent content = CreateContent(nodeId);
System.Collections.ObjectModel.ReadOnlyCollection<char> permissions = new List<char> { 'A' }.AsReadOnly();
ContentPermissionsResource resource = createWithNodeId
? new ContentPermissionsResource(content, nodeId, permissions)
: new ContentPermissionsResource(content, permissions);
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
@@ -76,20 +79,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static IContent CreateContent(int nodeId)
{
var contentType = ContentTypeBuilder.CreateBasicContentType();
ContentType contentType = ContentTypeBuilder.CreateBasicContentType();
return ContentBuilder.CreateBasicContent(contentType, nodeId);
}
private ContentPermissionsResourceHandler CreateHandler(int nodeId, string[] permissionsForPath)
{
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
var contentPermissions = CreateContentPermissions(nodeId, permissionsForPath);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor();
ContentPermissions contentPermissions = CreateContentPermissions(nodeId, permissionsForPath);
return new ContentPermissionsResourceHandler(mockBackOfficeSecurityAccessor.Object, contentPermissions);
}
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor()
{
var user = CreateUser();
User user = CreateUser();
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
@@ -97,11 +100,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser()
{
return new UserBuilder()
private static User CreateUser() =>
new UserBuilder()
.Build();
}
private static ContentPermissions CreateContentPermissions(int nodeId, string[] permissionsForPath)
{

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -6,7 +9,6 @@ using Moq;
using NUnit.Framework;
using Umbraco.Web.BackOffice.Authorization;
using Umbraco.Web.BackOffice.Security;
using Umbraco.Web.Common.Security;
namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
@@ -15,8 +17,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task With_Deny_Local_Login_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(denyLocalLogin: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
DenyLocalLoginHandler sut = CreateHandler(denyLocalLogin: true);
await sut.HandleAsync(authHandlerContext);
@@ -26,8 +28,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Without_Deny_Local_Login_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler();
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
DenyLocalLoginHandler sut = CreateHandler();
await sut.HandleAsync(authHandlerContext);
@@ -38,13 +40,13 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new DenyLocalLoginRequirement();
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object resource = new object();
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
}
private DenyLocalLoginHandler CreateHandler(bool denyLocalLogin = false)
{
var mockBackOfficeExternalLoginProviders = CreateMockBackOfficeExternalLoginProviders(denyLocalLogin);
Mock<IBackOfficeExternalLoginProviders> mockBackOfficeExternalLoginProviders = CreateMockBackOfficeExternalLoginProviders(denyLocalLogin);
return new DenyLocalLoginHandler(mockBackOfficeExternalLoginProviders.Object);
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
@@ -21,15 +24,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
private const string QueryStringName = "id";
private const int NodeId = 1000;
private static readonly Guid NodeGuid = Guid.NewGuid();
private static readonly Udi NodeUdi = UdiParser.Parse($"umb://document/{NodeGuid.ToString().ToLowerInvariant().Replace("-", string.Empty)}");
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(queryStringName: "xxx");
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringName: "xxx");
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -39,9 +42,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -52,9 +55,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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, startMediaId: 1001);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeId.ToString());
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, startMediaId: 1001);
await sut.HandleAsync(authHandlerContext);
@@ -65,9 +68,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Udi_Id_From_QueryString_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeUdi.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -78,9 +81,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Udi_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeUdi.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, startMediaId: 1001);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeUdi.ToString());
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, startMediaId: 1001);
await sut.HandleAsync(authHandlerContext);
@@ -91,9 +94,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Guid_Id_From_QueryString_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeGuid.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -104,9 +107,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Node_Guid_Id_From_QueryString_Without_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: NodeGuid.ToString());
var sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, startMediaId: 1001);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: s_nodeGuid.ToString());
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId, startMediaId: 1001);
await sut.HandleAsync(authHandlerContext);
@@ -117,9 +120,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[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);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue: "invalid");
MediaPermissionsQueryStringHandler sut = CreateHandler(mockHttpContextAccessor.Object, NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -130,7 +133,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new MediaPermissionsQueryStringRequirement(QueryStringName);
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object resource = new object();
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
}
@@ -152,9 +155,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private MediaPermissionsQueryStringHandler CreateHandler(IHttpContextAccessor httpContextAccessor, int nodeId, int startMediaId = -1)
{
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(startMediaId);
var mockEntityService = CreateMockEntityService();
var mediaPermissions = CreateMediaPermissions(mockEntityService.Object, nodeId);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(startMediaId);
Mock<IEntityService> mockEntityService = CreateMockEntityService();
MediaPermissions mediaPermissions = CreateMediaPermissions(mockEntityService.Object, nodeId);
return new MediaPermissionsQueryStringHandler(mockBackOfficeSecurityAccessor.Object, httpContextAccessor, mockEntityService.Object, mediaPermissions);
}
@@ -162,17 +165,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var mockEntityService = new Mock<IEntityService>();
mockEntityService
.Setup(x => x.GetId(It.Is<Udi>(y => y == NodeUdi)))
.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 == NodeGuid), It.Is<UmbracoObjectTypes>(y => y == UmbracoObjectTypes.Document)))
.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);
User user = CreateUser(startMediaId);
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
@@ -180,12 +183,10 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser(int startMediaId)
{
return new UserBuilder()
private static User CreateUser(int startMediaId) =>
new UserBuilder()
.WithStartMediaId(startMediaId)
.Build();
}
private static MediaPermissions CreateMediaPermissions(IEntityService entityService, int nodeId)
{
@@ -199,13 +200,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static IMedia CreateMedia(int nodeId)
{
var mediaType = MediaTypeBuilder.CreateSimpleMediaType("image", "Image");
MediaType mediaType = MediaTypeBuilder.CreateSimpleMediaType("image", "Image");
return MediaBuilder.CreateSimpleMedia(mediaType, "Test image", -1, nodeId);
}
private static void AssertMediaCached(Mock<IHttpContextAccessor> mockHttpContextAccessor)
{
private static void AssertMediaCached(Mock<IHttpContextAccessor> mockHttpContextAccessor) =>
Assert.AreEqual(NodeId, ((IMedia)mockHttpContextAccessor.Object.HttpContext.Items[typeof(IMedia).ToString()]).Id);
}
}
}

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -20,8 +23,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Node_Id_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
var sut = CreateHandler(NodeId);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
MediaPermissionsResourceHandler sut = CreateHandler(NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -31,8 +34,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Media_With_Permission_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
var sut = CreateHandler(NodeId);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
MediaPermissionsResourceHandler sut = CreateHandler(NodeId);
await sut.HandleAsync(authHandlerContext);
@@ -42,8 +45,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Node_Id_Withou_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
var sut = CreateHandler(NodeId, startMediaId: 1001);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId, createWithNodeId: true);
MediaPermissionsResourceHandler sut = CreateHandler(NodeId, startMediaId: 1001);
await sut.HandleAsync(authHandlerContext);
@@ -53,8 +56,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Resource_With_Media_Without_Permission_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
var sut = CreateHandler(NodeId, startMediaId: 1001);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext(NodeId);
MediaPermissionsResourceHandler sut = CreateHandler(NodeId, startMediaId: 1001);
await sut.HandleAsync(authHandlerContext);
@@ -65,8 +68,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new MediaPermissionsResourceRequirement();
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var media = CreateMedia(nodeId);
var resource = createWithNodeId
IMedia media = CreateMedia(nodeId);
MediaPermissionsResource resource = createWithNodeId
? new MediaPermissionsResource(nodeId)
: new MediaPermissionsResource(media);
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
@@ -74,20 +77,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static IMedia CreateMedia(int nodeId)
{
var mediaType = MediaTypeBuilder.CreateSimpleMediaType("image", "Image");
MediaType 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, new string[0]);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(startMediaId);
MediaPermissions contentPermissions = CreateMediaPermissions(nodeId);
return new MediaPermissionsResourceHandler(mockBackOfficeSecurityAccessor.Object, contentPermissions);
}
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(int startMediaId)
{
var user = CreateUser(startMediaId);
User user = CreateUser(startMediaId);
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
@@ -95,14 +98,12 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser(int startMediaId)
{
return new UserBuilder()
private static User CreateUser(int startMediaId) =>
new UserBuilder()
.WithStartMediaId(startMediaId)
.Build();
}
private static MediaPermissions CreateMediaPermissions(int nodeId, string[] permissionsForPath)
private static MediaPermissions CreateMediaPermissions(int nodeId)
{
var mockMediaService = new Mock<IMediaService>();
mockMediaService

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -17,8 +20,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Unauthorized_User_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler();
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
SectionHandler sut = CreateHandler();
await sut.HandleAsync(authHandlerContext);
@@ -28,8 +31,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_With_Section_Access_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(userIsAuthorized: true, userCanAccessContentSection: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
SectionHandler sut = CreateHandler(userIsAuthorized: true, userCanAccessContentSection: true);
await sut.HandleAsync(authHandlerContext);
@@ -39,8 +42,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_Without_Section_Access_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(userIsAuthorized: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
SectionHandler sut = CreateHandler(userIsAuthorized: true);
await sut.HandleAsync(authHandlerContext);
@@ -51,20 +54,20 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new SectionRequirement(Constants.Applications.Content, Constants.Applications.Media);
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object 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);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(userIsAuthorized, userCanAccessContentSection);
return new SectionHandler(mockBackOfficeSecurityAccessor.Object);
}
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(bool userIsAuthorized, bool userCanAccessContentSection)
{
var user = CreateUser();
User user = CreateUser();
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(userIsAuthorized ? user : null);
mockBackOfficeSecurity
@@ -78,10 +81,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser()
{
return new UserBuilder()
private static User CreateUser() =>
new UserBuilder()
.Build();
}
}
}

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -23,8 +26,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Unauthorized_User_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler();
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
TreeHandler sut = CreateHandler();
await sut.HandleAsync(authHandlerContext);
@@ -34,8 +37,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_With_Access_To_Tree_Section_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(userIsAuthorized: true, userCanAccessContentSection: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
TreeHandler sut = CreateHandler(userIsAuthorized: true, userCanAccessContentSection: true);
await sut.HandleAsync(authHandlerContext);
@@ -45,8 +48,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_Without_Access_To_Tree_Section_Is_Not_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(userIsAuthorized: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
TreeHandler sut = CreateHandler(userIsAuthorized: true);
await sut.HandleAsync(authHandlerContext);
@@ -57,14 +60,14 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new TreeRequirement(Tree1Alias, Tree2Alias);
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object 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);
Mock<ITreeService> mockTreeService = CreateMockTreeService();
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(userIsAuthorized, userCanAccessContentSection);
return new TreeHandler(mockTreeService.Object, mockBackOfficeSecurityAccessor.Object);
}
@@ -81,17 +84,15 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockTreeService;
}
private static Tree CreateTree(string alias, string sectionAlias)
{
return new TreeBuilder()
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();
User user = CreateUser();
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(userIsAuthorized ? user : null);
mockBackOfficeSecurity
@@ -105,10 +106,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser()
{
return new UserBuilder()
private static User CreateUser() => new UserBuilder()
.Build();
}
}
}

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
@@ -30,8 +33,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Missing_QueryString_Value_Is_Authorized()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler();
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
UserGroupHandler sut = CreateHandler();
await sut.HandleAsync(authHandlerContext);
@@ -41,8 +44,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task Admin_User_Is_Authorised()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: Group1Id.ToString(), userIsAdmin: true);
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
UserGroupHandler sut = CreateHandler(queryStringValue: Group1Id.ToString(), userIsAdmin: true);
await sut.HandleAsync(authHandlerContext);
@@ -52,8 +55,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_Matching_Single_Requested_Group_Id_Is_Authorised()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: Group1Id.ToString());
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
UserGroupHandler sut = CreateHandler(queryStringValue: Group1Id.ToString());
await sut.HandleAsync(authHandlerContext);
@@ -63,8 +66,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_Matching_One_Of_Requested_Group_Ids_Is_Authorised()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: $"{Group1Id},{Group2Id}");
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
UserGroupHandler sut = CreateHandler(queryStringValue: $"{Group1Id},{Group2Id}");
await sut.HandleAsync(authHandlerContext);
@@ -74,8 +77,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_Not_Matching_Single_Requested_Group_Id_Is_Not_Authorised()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: Group2Id.ToString());
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
UserGroupHandler sut = CreateHandler(queryStringValue: Group2Id.ToString());
await sut.HandleAsync(authHandlerContext);
@@ -85,8 +88,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
[Test]
public async Task User_Not_Matching_Any_Of_Requested_Group_Ids_Is_Not_Authorised()
{
var authHandlerContext = CreateAuthorizationHandlerContext();
var sut = CreateHandler(queryStringValue: $"{Group2Id},{Group3Id}");
AuthorizationHandlerContext authHandlerContext = CreateAuthorizationHandlerContext();
UserGroupHandler sut = CreateHandler(queryStringValue: $"{Group2Id},{Group3Id}");
await sut.HandleAsync(authHandlerContext);
@@ -97,21 +100,21 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
{
var requirement = new UserGroupRequirement(QueryStringName);
var user = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim>()));
var resource = new object();
object resource = new object();
return new AuthorizationHandlerContext(new List<IAuthorizationRequirement> { requirement }, user, resource);
}
private UserGroupHandler CreateHandler(string queryStringValue = "", bool userIsAdmin = false)
{
var mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue);
Mock<IHttpContextAccessor> mockHttpContextAccessor = CreateMockHttpContextAccessor(queryStringValue);
var mockUserService = CreateMockUserService();
Mock<IUserService> mockUserService = CreateMockUserService();
var mockContentService = new Mock<IContentService>();
var mockMediaService = new Mock<IMediaService>();
var mockEntityService = new Mock<IEntityService>();
var mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(userIsAdmin);
Mock<IBackOfficeSecurityAccessor> mockBackOfficeSecurityAccessor = CreateMockBackOfficeSecurityAccessor(userIsAdmin);
return new UserGroupHandler(mockHttpContextAccessor.Object, mockUserService.Object, mockContentService.Object, mockMediaService.Object, mockEntityService.Object, mockBackOfficeSecurityAccessor.Object);
}
@@ -151,7 +154,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
private static Mock<IBackOfficeSecurityAccessor> CreateMockBackOfficeSecurityAccessor(bool userIsAdmin)
{
var user = CreateUser(userIsAdmin);
User user = CreateUser(userIsAdmin);
var mockBackOfficeSecurity = new Mock<IBackOfficeSecurity>();
mockBackOfficeSecurity.SetupGet(x => x.CurrentUser).Returns(user);
var mockBackOfficeSecurityAccessor = new Mock<IBackOfficeSecurityAccessor>();
@@ -159,21 +162,17 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Web.BackOffice.Authorization
return mockBackOfficeSecurityAccessor;
}
private static User CreateUser(bool isAdmin = false)
{
return new UserBuilder()
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)
{
return new UserGroupBuilder()
private IUserGroup CreateUserGroup(int id, string alias) =>
new UserGroupBuilder()
.WithId(id)
.WithAlias(alias)
.Build();
}
}
}

View File

@@ -1,7 +1,12 @@
using System.Linq;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Umbraco.Core;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
@@ -14,25 +19,34 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class AdminUsersHandler : MustSatisfyRequirementAuthorizationHandler<AdminUsersRequirement>
{
private readonly IHttpContextAccessor _httpContextAcessor;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUserService _userService;
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly UserEditorAuthorizationHelper _userEditorAuthorizationHelper;
public AdminUsersHandler(IHttpContextAccessor httpContextAcessor,
IUserService userService,
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
UserEditorAuthorizationHelper userEditorAuthorizationHelper)
/// <summary>
/// Initializes a new instance of the <see cref="AdminUsersHandler"/> class.
/// </summary>
/// <param name="httpContextAccessor">Accessor for the HTTP context of the current request.</param>
/// <param name="userService">Service for user related operations.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
/// <param name="userEditorAuthorizationHelper">Helper for user authorization checks.</param>
public AdminUsersHandler(
IHttpContextAccessor httpContextAccessor,
IUserService userService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
UserEditorAuthorizationHelper userEditorAuthorizationHelper)
{
_httpContextAcessor = httpContextAcessor;
_httpContextAccessor = httpContextAccessor;
_userService = userService;
_backofficeSecurityAccessor = backofficeSecurityAccessor;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_userEditorAuthorizationHelper = userEditorAuthorizationHelper;
}
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, AdminUsersRequirement requirement)
{
var queryString = _httpContextAcessor.HttpContext?.Request.Query[requirement.QueryStringName];
StringValues? queryString = _httpContextAccessor.HttpContext?.Request.Query[requirement.QueryStringName];
if (!queryString.HasValue || !queryString.Value.Any())
{
// Must succeed this requirement since we cannot process it.
@@ -46,12 +60,13 @@ namespace Umbraco.Web.BackOffice.Authorization
}
else
{
var ids = _httpContextAcessor.HttpContext.Request.Query.Where(x => x.Key == requirement.QueryStringName).ToList();
var ids = _httpContextAccessor.HttpContext.Request.Query.Where(x => x.Key == requirement.QueryStringName).ToList();
if (ids.Count == 0)
{
// Must succeed this requirement since we cannot process it.
return Task.FromResult(true);
}
userIds = ids
.Select(x => x.Value.ToString())
.Select(x => x.TryConvertTo<int>()).Where(x => x.Success).Select(x => x.Result).ToArray();
@@ -63,8 +78,8 @@ namespace Umbraco.Web.BackOffice.Authorization
return Task.FromResult(true);
}
var users = _userService.GetUsersById(userIds);
var isAuth = users.All(user => _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser, user, null, null, null) != false);
IEnumerable<Core.Models.Membership.IUser> users = _userService.GetUsersById(userIds);
var isAuth = users.All(user => _userEditorAuthorizationHelper.IsAuthorized(_backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser, user, null, null, null) != false);
return Task.FromResult(isAuth);
}

View File

@@ -1,4 +1,7 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
@@ -7,11 +10,15 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class AdminUsersRequirement : IAuthorizationRequirement
{
public AdminUsersRequirement(string queryStringName = "id")
{
QueryStringName = queryStringName;
}
/// <summary>
/// Initializes a new instance of the <see cref="AdminUsersRequirement"/> class.
/// </summary>
/// <param name="queryStringName">Query string name from which to authorize values.</param>
public AdminUsersRequirement(string queryStringName = "id") => QueryStringName = queryStringName;
/// <summary>
/// Gets the query string name from which to authorize values.
/// </summary>
public string QueryStringName { get; }
}
}

View File

@@ -1,3 +1,6 @@
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Umbraco.Core;

View File

@@ -1,4 +1,7 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
@@ -7,11 +10,15 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class BackOfficeRequirement : IAuthorizationRequirement
{
public BackOfficeRequirement(bool requireApproval = true)
{
RequireApproval = requireApproval;
}
/// <summary>
/// Initializes a new instance of the <see cref="BackOfficeRequirement"/> class.
/// </summary>
/// <param name="requireApproval">Flag for whether back-office user approval is required.</param>
public BackOfficeRequirement(bool requireApproval = true) => RequireApproval = requireApproval;
/// <summary>
/// Gets a value indicating whether back-office user approval is required.
/// </summary>
public bool RequireApproval { get; }
}
}

View File

@@ -1,7 +1,10 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Entities;
@@ -11,7 +14,7 @@ using Umbraco.Core.Services;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// The user must have access to all descendant nodes of the content item in order to continue
/// The user must have access to all descendant nodes of the content item in order to continue.
/// </summary>
public class ContentPermissionsPublishBranchHandler : MustSatisfyRequirementAuthorizationHandler<ContentPermissionsPublishBranchRequirement, IContent>
{
@@ -19,6 +22,12 @@ namespace Umbraco.Web.BackOffice.Authorization
private readonly ContentPermissions _contentPermissions;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
/// <summary>
/// Initializes a new instance of the <see cref="ContentPermissionsPublishBranchHandler"/> class.
/// </summary>
/// <param name="entityService">Service for entity operations.</param>
/// <param name="contentPermissions">per for user content authorization checks.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
public ContentPermissionsPublishBranchHandler(
IEntityService entityService,
ContentPermissions contentPermissions,
@@ -29,9 +38,10 @@ namespace Umbraco.Web.BackOffice.Authorization
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, ContentPermissionsPublishBranchRequirement requirement, IContent resource)
{
var currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
Core.Models.Membership.IUser currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
var denied = new List<IUmbracoEntity>();
var page = 0;
@@ -40,16 +50,22 @@ namespace Umbraco.Web.BackOffice.Authorization
while (page * pageSize < total)
{
var descendants = _entityService.GetPagedDescendants(resource.Id, UmbracoObjectTypes.Document, page++, pageSize, out total,
// Order by shallowest to deepest, this allows us to check permissions from top to bottom so we can exit
// early if a permission higher up fails.
ordering: Ordering.By("path", Direction.Ascending));
// Order descendents by shallowest to deepest, this allows us to check permissions from top to bottom so we can exit
// early if a permission higher up fails.
IEnumerable<IEntitySlim> descendants = _entityService.GetPagedDescendants(
resource.Id,
UmbracoObjectTypes.Document,
page++,
pageSize,
out total,
ordering: Ordering.By("path", Direction.Ascending));
foreach (var c in descendants)
foreach (IEntitySlim c in descendants)
{
// If this item's path has already been denied or if the user doesn't have access to it, add to the deny list.
if (denied.Any(x => c.Path.StartsWith($"{x.Path},"))
|| (_contentPermissions.CheckPermissions(c,
if (denied.Any(x => c.Path.StartsWith($"{x.Path},")) ||
(_contentPermissions.CheckPermissions(
c,
currentUser,
requirement.Permission) == ContentPermissions.ContentAccess.Denied))
{

View File

@@ -1,4 +1,7 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
@@ -7,11 +10,15 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class ContentPermissionsPublishBranchRequirement : IAuthorizationRequirement
{
public ContentPermissionsPublishBranchRequirement(char permission)
{
Permission = permission;
}
/// <summary>
/// Initializes a new instance of the <see cref="ContentPermissionsPublishBranchRequirement"/> class.
/// </summary>
/// <param name="permission">Permission to check.</param>
public ContentPermissionsPublishBranchRequirement(char permission) => Permission = permission;
/// <summary>
/// Gets a value for the permission to check.
/// </summary>
public char Permission { get; }
}
}

View File

@@ -1,8 +1,10 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Umbraco.Core;
using Microsoft.Extensions.Primitives;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
@@ -10,28 +12,33 @@ using Umbraco.Core.Services;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Used to authorize if the user has the correct permission access to the content for the content id specified in a query string
/// Used to authorize if the user has the correct permission access to the content for the content id specified in a query string.
/// </summary>
public class ContentPermissionsQueryStringHandler : PermissionsQueryStringHandler<ContentPermissionsQueryStringRequirement>
{
private readonly ContentPermissions _contentPermissions;
/// <summary>
/// Initializes a new instance of the <see cref="ContentPermissionsQueryStringHandler"/> class.
/// </summary>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
/// <param name="httpContextAccessor">Accessor for the HTTP context of the current request.</param>
/// <param name="entityService">Service for entity operations.</param>
/// <param name="contentPermissions">Helper for content authorization checks.</param>
public ContentPermissionsQueryStringHandler(
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
IHttpContextAccessor httpContextAccessor,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IHttpContextAccessor httpContextAccessor,
IEntityService entityService,
ContentPermissions contentPermissions)
: base(backofficeSecurityAccessor, httpContextAccessor, entityService)
{
_contentPermissions = contentPermissions;
}
: base(backOfficeSecurityAccessor, httpContextAccessor, entityService) => _contentPermissions = contentPermissions;
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, ContentPermissionsQueryStringRequirement requirement)
{
int nodeId;
if (requirement.NodeId.HasValue == false)
{
if (!HttpContextAccessor.HttpContext.Request.Query.TryGetValue(requirement.QueryStringName, out var routeVal))
if (!HttpContextAccessor.HttpContext.Request.Query.TryGetValue(requirement.QueryStringName, out StringValues routeVal))
{
// Must succeed this requirement since we cannot process it
return Task.FromResult(true);
@@ -52,8 +59,9 @@ namespace Umbraco.Web.BackOffice.Authorization
nodeId = requirement.NodeId.Value;
}
var permissionResult = _contentPermissions.CheckPermissions(nodeId,
BackofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
ContentPermissions.ContentAccess permissionResult = _contentPermissions.CheckPermissions(
nodeId,
BackOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
out IContent contentItem,
new[] { requirement.PermissionToCheck });

View File

@@ -1,19 +1,20 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// An authorization requirement for <see cref="ContentPermissionsQueryStringHandler"/>
/// </summary>
public class ContentPermissionsQueryStringRequirement : IAuthorizationRequirement
{
/// <summary>
/// Create an authorization requirement for a specific node id
/// Initializes a new instance of the <see cref="ContentPermissionsQueryStringRequirement"/> class for a specific node id.
/// </summary>
/// <param name="nodeId"></param>
/// <param name="permissionToCheck"></param>
/// <param name="nodeId">The node Id.</param>
/// <param name="permissionToCheck">The permission to authorize the current user against.</param>
public ContentPermissionsQueryStringRequirement(int nodeId, char permissionToCheck)
{
NodeId = nodeId;
@@ -21,18 +22,30 @@ namespace Umbraco.Web.BackOffice.Authorization
}
/// <summary>
/// Create an authorization requirement for a node id based on a query string parameter
/// Initializes a new instance of the <see cref="ContentPermissionsQueryStringRequirement"/> class for a
/// node id based on a query string parameter.
/// </summary>
/// <param name="paramName"></param>
/// <param name="permissionToCheck"></param>
/// <param name="paramName">The querystring parameter name.</param>
/// <param name="permissionToCheck">The permission to authorize the current user against.</param>
public ContentPermissionsQueryStringRequirement(char permissionToCheck, string paramName = "id")
{
QueryStringName = paramName;
PermissionToCheck = permissionToCheck;
}
/// <summary>
/// Gets the specific node Id.
/// </summary>
public int? NodeId { get; }
/// <summary>
/// Gets the querystring parameter name.
/// </summary>
public string QueryStringName { get; }
/// <summary>
/// Gets the permission to authorize the current user against.
/// </summary>
public char PermissionToCheck { get; }
}
}

View File

@@ -1,4 +1,7 @@
using System.Collections.Generic;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using Umbraco.Core.Models;
namespace Umbraco.Web.BackOffice.Authorization
@@ -8,27 +11,54 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class ContentPermissionsResource
{
/// <summary>
/// Initializes a new instance of the <see cref="ContentPermissionsResource"/> class.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="permissionToCheck">The permission to authorize.</param>
public ContentPermissionsResource(IContent content, char permissionToCheck)
{
PermissionsToCheck = new List<char> { permissionToCheck };
Content = content;
}
public ContentPermissionsResource(IContent content, IReadOnlyList<char> permissionToCheck)
/// <summary>
/// Initializes a new instance of the <see cref="ContentPermissionsResource"/> class.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="permissionsToCheck">The collection of permissions to authorize.</param>
public ContentPermissionsResource(IContent content, IReadOnlyList<char> permissionsToCheck)
{
Content = content;
PermissionsToCheck = permissionToCheck;
PermissionsToCheck = permissionsToCheck;
}
public ContentPermissionsResource(IContent content, int nodeId, IReadOnlyList<char> permissionToCheck)
/// <summary>
/// Initializes a new instance of the <see cref="ContentPermissionsResource"/> class.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="nodeId">The node Id.</param>
/// <param name="permissionsToCheck">The collection of permissions to authorize.</param>
public ContentPermissionsResource(IContent content, int nodeId, IReadOnlyList<char> permissionsToCheck)
{
Content = content;
NodeId = nodeId;
PermissionsToCheck = permissionToCheck;
PermissionsToCheck = permissionsToCheck;
}
public int? NodeId { get; }
/// <summary>
/// Gets the node Id.
/// </summary>
public int? NodeId { get; }
/// <summary>
/// Gets the collection of permissions to authorize.
/// </summary>
public IReadOnlyList<char> PermissionsToCheck { get; }
/// <summary>
/// Gets the content.
/// </summary>
public IContent Content { get; }
}
}

View File

@@ -1,4 +1,7 @@
using System.Threading.Tasks;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
@@ -10,28 +13,34 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class ContentPermissionsResourceHandler : MustSatisfyRequirementAuthorizationHandler<ContentPermissionsResourceRequirement, ContentPermissionsResource>
{
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly ContentPermissions _contentPermissions;
/// <summary>
/// Initializes a new instance of the <see cref="ContentPermissionsResourceHandler"/> class.
/// </summary>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
/// <param name="contentPermissions">Helper for content authorization checks.</param>
public ContentPermissionsResourceHandler(
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
ContentPermissions contentPermissions)
{
_backofficeSecurityAccessor = backofficeSecurityAccessor;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_contentPermissions = contentPermissions;
}
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, ContentPermissionsResourceRequirement requirement, ContentPermissionsResource resource)
{
var permissionResult = resource.NodeId.HasValue
ContentPermissions.ContentAccess permissionResult = resource.NodeId.HasValue
? _contentPermissions.CheckPermissions(
resource.NodeId.Value,
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
_backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
out IContent _,
resource.PermissionsToCheck)
: _contentPermissions.CheckPermissions(
resource.Content,
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
_backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
resource.PermissionsToCheck);
return Task.FromResult(permissionResult != ContentPermissions.ContentAccess.Denied);

View File

@@ -1,9 +1,10 @@
using Microsoft.AspNetCore.Authorization;
using Umbraco.Web.Actions;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// An authorization requirement for <see cref="ContentPermissionsResourceHandler"/>
/// </summary>

View File

@@ -1,26 +1,27 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Umbraco.Web.BackOffice.Security;
using Umbraco.Web.Common.Security;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Ensures the resource cannot be accessed if <see cref="IBackOfficeExternalLoginProviders.HasDenyLocalLogin"/> returns true
/// Ensures the resource cannot be accessed if <see cref="IBackOfficeExternalLoginProviders.HasDenyLocalLogin"/> returns true.
/// </summary>
public class DenyLocalLoginHandler : MustSatisfyRequirementAuthorizationHandler<DenyLocalLoginRequirement>
{
private readonly IBackOfficeExternalLoginProviders _externalLogins;
public DenyLocalLoginHandler(IBackOfficeExternalLoginProviders externalLogins)
{
_externalLogins = externalLogins;
}
/// <summary>
/// Initializes a new instance of the <see cref="DenyLocalLoginHandler"/> class.
/// </summary>
/// <param name="externalLogins">Provides access to <see cref="BackOfficeExternalLoginProvider" /> instances.</param>
public DenyLocalLoginHandler(IBackOfficeExternalLoginProviders externalLogins) => _externalLogins = externalLogins;
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, DenyLocalLoginRequirement requirement)
{
return Task.FromResult(!_externalLogins.HasDenyLocalLogin());
}
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, DenyLocalLoginRequirement requirement) =>
Task.FromResult(!_externalLogins.HasDenyLocalLogin());
}
}

View File

@@ -1,9 +1,12 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Marker requirement for the <see cref="DenyLocalLoginHandler"/>
/// Marker requirement for the <see cref="DenyLocalLoginHandler"/>.
/// </summary>
public class DenyLocalLoginRequirement : IAuthorizationRequirement
{

View File

@@ -1,29 +1,41 @@
using System.Threading.Tasks;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Used to authorize if the user has the correct permission access to the media for the media id specified in a query string.
/// </summary>
public class MediaPermissionsQueryStringHandler : PermissionsQueryStringHandler<MediaPermissionsQueryStringRequirement>
{
private readonly MediaPermissions _mediaPermissions;
/// <summary>
/// Initializes a new instance of the <see cref="MediaPermissionsQueryStringHandler"/> class.
/// </summary>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
/// <param name="httpContextAccessor">Accessor for the HTTP context of the current request.</param>
/// <param name="entityService">Service for entity operations.</param>
/// <param name="mediaPermissions">Helper for media authorization checks.</param>
public MediaPermissionsQueryStringHandler(
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IHttpContextAccessor httpContextAccessor,
IEntityService entityService,
MediaPermissions mediaPermissions)
: base(backofficeSecurityAccessor, httpContextAccessor, entityService)
{
_mediaPermissions = mediaPermissions;
}
: base(backOfficeSecurityAccessor, httpContextAccessor, entityService) => _mediaPermissions = mediaPermissions;
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, MediaPermissionsQueryStringRequirement requirement)
{
if (!HttpContextAccessor.HttpContext.Request.Query.TryGetValue(requirement.QueryStringName, out var routeVal))
if (!HttpContextAccessor.HttpContext.Request.Query.TryGetValue(requirement.QueryStringName, out StringValues routeVal))
{
// Must succeed this requirement since we cannot process it.
return Task.FromResult(true);
@@ -37,10 +49,10 @@ namespace Umbraco.Web.BackOffice.Authorization
return Task.FromResult(true);
}
var permissionResult = _mediaPermissions.CheckPermissions(
BackofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
MediaPermissions.MediaAccess permissionResult = _mediaPermissions.CheckPermissions(
BackOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
nodeId,
out var mediaItem);
out IMedia mediaItem);
if (mediaItem != null)
{
@@ -53,6 +65,6 @@ namespace Umbraco.Web.BackOffice.Authorization
MediaPermissions.MediaAccess.Denied => Task.FromResult(false),
_ => Task.FromResult(true),
};
}
}
}
}

View File

@@ -1,14 +1,24 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// An authorization requirement for <see cref="MediaPermissionsQueryStringHandler"/>
/// </summary>
public class MediaPermissionsQueryStringRequirement : IAuthorizationRequirement
{
public MediaPermissionsQueryStringRequirement(string paramName)
{
QueryStringName = paramName;
}
/// <summary>
/// Initializes a new instance of the <see cref="MediaPermissionsQueryStringRequirement"/> class.
/// </summary>
/// <param name="paramName">Querystring paramter name.</param>
public MediaPermissionsQueryStringRequirement(string paramName) => QueryStringName = paramName;
/// <summary>
/// Gets the querystring paramter name.
/// </summary>
public string QueryStringName { get; }
}
}

View File

@@ -1,4 +1,7 @@
using Umbraco.Core.Models;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Umbraco.Core.Models;
namespace Umbraco.Web.BackOffice.Authorization
{

View File

@@ -1,36 +1,45 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Umbraco.Core.Models;
using Umbraco.Core.Security;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Used to authorize if the user has the correct permission access to the content for the <see cref="IContent"/> specified
/// Used to authorize if the user has the correct permission access to the content for the <see cref="IContent"/> specified.
/// </summary>
public class MediaPermissionsResourceHandler : MustSatisfyRequirementAuthorizationHandler<MediaPermissionsResourceRequirement, MediaPermissionsResource>
{
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
private readonly MediaPermissions _mediaPermissions;
/// <summary>
/// Initializes a new instance of the <see cref="MediaPermissionsResourceHandler"/> class.
/// </summary>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
/// <param name="mediaPermissions">Helper for media authorization checks.</param>
public MediaPermissionsResourceHandler(
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
MediaPermissions mediaPermissions)
{
_backofficeSecurityAccessor = backofficeSecurityAccessor;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_mediaPermissions = mediaPermissions;
}
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, MediaPermissionsResourceRequirement requirement, MediaPermissionsResource resource)
{
var permissionResult = resource.NodeId.HasValue
MediaPermissions.MediaAccess permissionResult = resource.NodeId.HasValue
? _mediaPermissions.CheckPermissions(
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
_backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
resource.NodeId.Value,
out _)
: _mediaPermissions.CheckPermissions(
resource.Media,
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser);
_backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser);
return Task.FromResult(permissionResult != MediaPermissions.MediaAccess.Denied);
}

View File

@@ -1,13 +1,14 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// An authorization requirement for <see cref="MediaPermissionsResourceHandler"/>
/// </summary>
public class MediaPermissionsResourceRequirement : IAuthorizationRequirement
{
}
}

View File

@@ -1,18 +1,23 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Abstract handler that must satisfy the requirement so Succeed or Fail will be called no matter what
/// Abstract handler that must satisfy the requirement so Succeed or Fail will be called no matter what.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="T">Authorization requirement.</typeparam>
/// <remarks>
/// aspnetcore Authz handlers are not required to satisfy the requirement and generally don't explicitly call Fail when the requirement
/// isn't satisfied, however in many simple cases explicitly calling Succeed or Fail is what we want which is what this class is used for.
/// </remarks>
public abstract class MustSatisfyRequirementAuthorizationHandler<T> : AuthorizationHandler<T> where T : IAuthorizationRequirement
public abstract class MustSatisfyRequirementAuthorizationHandler<T> : AuthorizationHandler<T>
where T : IAuthorizationRequirement
{
/// <inheritdoc/>
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, T requirement)
{
var isAuth = await IsAuthorized(context, requirement);
@@ -29,23 +34,25 @@ namespace Umbraco.Web.BackOffice.Authorization
/// <summary>
/// Return true if the requirement is succeeded or ignored, return false if the requirement is explicitly not met
/// </summary>
/// <param name="context"></param>
/// <param name="requirement"></param>
/// <returns></returns>
/// <param name="context">The authorization context.</param>
/// <param name="requirement">The authorization requirement.</param>
/// <returns>True if request is authorized, false if not.</returns>
protected abstract Task<bool> IsAuthorized(AuthorizationHandlerContext context, T requirement);
}
/// <summary>
/// Abstract handler that must satisfy the requirement so Succeed or Fail will be called no matter what
/// Abstract handler that must satisfy the requirement so Succeed or Fail will be called no matter what.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResource"></typeparam>
/// <typeparam name="T">Authorization requirement.</typeparam>
/// <typeparam name="TResource">Resource to authorize access to.</typeparam>
/// <remarks>
/// aspnetcore Authz handlers are not required to satisfy the requirement and generally don't explicitly call Fail when the requirement
/// isn't satisfied, however in many simple cases explicitly calling Succeed or Fail is what we want which is what this class is used for.
/// </remarks>
public abstract class MustSatisfyRequirementAuthorizationHandler<T, TResource> : AuthorizationHandler<T, TResource> where T : IAuthorizationRequirement
public abstract class MustSatisfyRequirementAuthorizationHandler<T, TResource> : AuthorizationHandler<T, TResource>
where T : IAuthorizationRequirement
{
/// <inheritdoc/>
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, T requirement, TResource resource)
{
var isAuth = await IsAuthorized(context, requirement, resource);
@@ -62,9 +69,10 @@ namespace Umbraco.Web.BackOffice.Authorization
/// <summary>
/// Return true if the requirement is succeeded or ignored, return false if the requirement is explicitly not met
/// </summary>
/// <param name="context"></param>
/// <param name="requirement"></param>
/// <returns></returns>
/// <param name="context">The authorization context.</param>
/// <param name="requirement">The authorization requirement.</param>
/// <param name="resource">The resource to authorize access to.</param>
/// <returns>True if request is authorized, false if not.</returns>
protected abstract Task<bool> IsAuthorized(AuthorizationHandlerContext context, T requirement, TResource resource);
}
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Umbraco.Core;
@@ -8,25 +11,50 @@ using Umbraco.Core.Services;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Abstract base class providing common functionality for authorization checks based on querystrings.
/// </summary>
/// <typeparam name="T">Authorization requirement</typeparam>
public abstract class PermissionsQueryStringHandler<T> : MustSatisfyRequirementAuthorizationHandler<T>
where T : IAuthorizationRequirement
{
/// <summary>
/// Initializes a new instance of the <see cref="PermissionsQueryStringHandler{T}"/> class.
/// </summary>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
/// <param name="httpContextAccessor">Accessor for the HTTP context of the current request.</param>
/// <param name="entityService">Service for entity operations.</param>
public PermissionsQueryStringHandler(
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IHttpContextAccessor httpContextAccessor,
IEntityService entityService)
{
BackofficeSecurityAccessor = backofficeSecurityAccessor;
BackOfficeSecurityAccessor = backOfficeSecurityAccessor;
HttpContextAccessor = httpContextAccessor;
EntityService = entityService;
}
protected IBackOfficeSecurityAccessor BackofficeSecurityAccessor { get; set; }
/// <summary>
/// Gets or sets the <see cref="IBackOfficeSecurityAccessor" /> instance.
/// </summary>
protected IBackOfficeSecurityAccessor BackOfficeSecurityAccessor { get; set; }
/// <summary>
/// Gets or sets the <see cref="IHttpContextAccessor" /> instance.
/// </summary>
protected IHttpContextAccessor HttpContextAccessor { get; set; }
/// <summary>
/// Gets or sets the <see cref="IEntityService" /> instance.
/// </summary>
protected IEntityService EntityService { get; set; }
/// <summary>
/// Attempts to parse a node ID from a string representation found in a querystring value.
/// </summary>
/// <param name="argument">Querystring value.</param>
/// <param name="nodeId">Output parsed Id.</param>
/// <returns>True of node ID could be parased, false it not.</returns>
protected bool TryParseNodeId(string argument, out int nodeId)
{
// If the argument is an int, it will parse and can be assigned to nodeId.
@@ -38,12 +66,12 @@ namespace Umbraco.Web.BackOffice.Authorization
nodeId = parsedId;
return true;
}
else if (UdiParser.TryParse(argument, true, out var udi))
else if (UdiParser.TryParse(argument, true, out Udi udi))
{
nodeId = EntityService.GetId(udi).Result;
return true;
}
else if (Guid.TryParse(argument, out var key))
else if (Guid.TryParse(argument, out Guid key))
{
nodeId = EntityService.GetId(key, UmbracoObjectTypes.Document).Result;
return true;

View File

@@ -1,11 +1,13 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Umbraco.Core.Security;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Ensures that the current user has access to the section
/// </summary>
@@ -14,18 +16,21 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </remarks>
public class SectionHandler : MustSatisfyRequirementAuthorizationHandler<SectionRequirement>
{
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public SectionHandler(IBackOfficeSecurityAccessor backofficeSecurityAccessor)
{
_backofficeSecurityAccessor = backofficeSecurityAccessor;
}
/// <summary>
/// Initializes a new instance of the <see cref="SectionHandler"/> class.
/// </summary>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
public SectionHandler(IBackOfficeSecurityAccessor backOfficeSecurityAccessor) => _backOfficeSecurityAccessor = backOfficeSecurityAccessor;
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, SectionRequirement requirement)
{
var authorized = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
&& requirement.SectionAliases.Any(app => _backofficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
app, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
var authorized = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null &&
requirement.SectionAliases
.Any(app => _backOfficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
app, _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
return Task.FromResult(authorized);
}

View File

@@ -1,5 +1,8 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
@@ -9,10 +12,14 @@ namespace Umbraco.Web.BackOffice.Authorization
public class SectionRequirement : IAuthorizationRequirement
{
/// <summary>
/// The aliases for sections that the user will need access to
/// Initializes a new instance of the <see cref="SectionRequirement"/> class.
/// </summary>
/// <param name="aliases">Aliases for sections that the user will need access to.</param>
public SectionRequirement(params string[] aliases) => SectionAliases = aliases;
/// <summary>
/// Gets the aliases for sections that the user will need access to.
/// </summary>
public IReadOnlyCollection<string> SectionAliases { get; }
public SectionRequirement(params string[] aliases) => SectionAliases = aliases;
}
}

View File

@@ -1,14 +1,16 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Linq;
using Umbraco.Core;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Umbraco.Core;
using Umbraco.Core.Security;
using Umbraco.Web.Services;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Ensures that the current user has access to the section for which the specified tree(s) belongs
/// </summary>
@@ -18,40 +20,35 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </remarks>
public class TreeHandler : MustSatisfyRequirementAuthorizationHandler<TreeRequirement>
{
private readonly ITreeService _treeService;
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
/// <summary>
/// Constructor to set authorization to be based on a tree alias for which application security will be applied
/// Initializes a new instance of the <see cref="TreeHandler"/> class.
/// </summary>
/// <param name="treeService"></param>
/// <param name="backofficeSecurityAccessor"></param>
/// <param name="treeAliases">
/// If the user has access to the application that the treeAlias is specified in, they will be authorized.
/// Multiple trees may be specified.
/// </param>
public TreeHandler(ITreeService treeService, IBackOfficeSecurityAccessor backofficeSecurityAccessor)
/// <param name="treeService">Service for section tree operations.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
public TreeHandler(ITreeService treeService, IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_treeService = treeService ?? throw new ArgumentNullException(nameof(treeService));
_backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
_backOfficeSecurityAccessor = backOfficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backOfficeSecurityAccessor));
}
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, TreeRequirement requirement)
{
var apps = requirement.TreeAliases.Select(x => _treeService
.GetByAlias(x))
var apps = requirement.TreeAliases
.Select(x => _treeService.GetByAlias(x))
.WhereNotNull()
.Select(x => x.SectionAlias)
.Distinct()
.ToArray();
var isAuth = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
&& apps.Any(app => _backofficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
app, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
var isAuth = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null &&
apps.Any(app => _backOfficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
app, _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
return Task.FromResult(isAuth);
}
}
}

View File

@@ -1,19 +1,25 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
/// <summary>
/// Authorization requirements for <see cref="TreeHandler"/>
/// </summary>
public class TreeRequirement : IAuthorizationRequirement
{
/// <summary>
/// The aliases for trees that the user will need access to
/// Initializes a new instance of the <see cref="TreeRequirement"/> class.
/// </summary>
/// <param name="aliases">The aliases for trees that the user will need access to.</param>
public TreeRequirement(params string[] aliases) => TreeAliases = aliases;
/// <summary>
/// Gets the aliases for trees that the user will need access to.
/// </summary>
public IReadOnlyCollection<string> TreeAliases { get; }
public TreeRequirement(params string[] aliases) => TreeAliases = aliases;
}
}

View File

@@ -1,8 +1,14 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Umbraco.Core;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Web.BackOffice.Controllers;
@@ -14,40 +20,51 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class UserGroupHandler : MustSatisfyRequirementAuthorizationHandler<UserGroupRequirement>
{
private readonly IHttpContextAccessor _httpContextAcessor;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUserService _userService;
private readonly IContentService _contentService;
private readonly IMediaService _mediaService;
private readonly IEntityService _entityService;
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor;
public UserGroupHandler(IHttpContextAccessor httpContextAcessor,
IUserService userService,
IContentService contentService,
IMediaService mediaService,
IEntityService entityService,
IBackOfficeSecurityAccessor backofficeSecurityAccessor)
/// <summary>
/// Initializes a new instance of the <see cref="UserGroupHandler"/> class.
/// </summary>
/// <param name="httpContextAccessor">Accessor for the HTTP context of the current request.</param>
/// <param name="userService">Service for user related operations.</param>
/// <param name="contentService">Service for content related operations.</param>
/// <param name="mediaService">Service for media related operations.</param>
/// <param name="entityService">Service for entity related operations.</param>
/// <param name="backOfficeSecurityAccessor">Accessor for back-office security.</param>
public UserGroupHandler(
IHttpContextAccessor httpContextAccessor,
IUserService userService,
IContentService contentService,
IMediaService mediaService,
IEntityService entityService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
{
_httpContextAcessor = httpContextAcessor;
_httpContextAccessor = httpContextAccessor;
_userService = userService;
_contentService = contentService;
_mediaService = mediaService;
_entityService = entityService;
_backofficeSecurityAccessor = backofficeSecurityAccessor;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
}
/// <inheritdoc/>
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, UserGroupRequirement requirement)
{
var currentUser = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
IUser currentUser = _backOfficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
var queryString = _httpContextAcessor.HttpContext?.Request.Query;
IQueryCollection queryString = _httpContextAccessor.HttpContext?.Request.Query;
if (queryString == null)
{
// Must succeed this requirement since we cannot process it.
return Task.FromResult(true);
}
}
var ids = queryString.Where(x => x.Key == requirement.QueryStringName).ToArray();
KeyValuePair<string, StringValues>[] ids = queryString.Where(x => x.Key == requirement.QueryStringName).ToArray();
if (ids.Length == 0)
{
// Must succeed this requirement since we cannot process it.
@@ -64,10 +81,9 @@ namespace Umbraco.Web.BackOffice.Authorization
_mediaService,
_entityService);
var isAuth = authHelper.AuthorizeGroupAccess(currentUser, intIds);
Attempt<string> isAuth = authHelper.AuthorizeGroupAccess(currentUser, intIds);
return Task.FromResult(isAuth.Success);
}
}
}

View File

@@ -1,4 +1,7 @@
using Microsoft.AspNetCore.Authorization;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Web.BackOffice.Authorization
{
@@ -7,11 +10,15 @@ namespace Umbraco.Web.BackOffice.Authorization
/// </summary>
public class UserGroupRequirement : IAuthorizationRequirement
{
public UserGroupRequirement(string queryStringName = "id")
{
QueryStringName = queryStringName;
}
/// <summary>
/// Initializes a new instance of the <see cref="UserGroupRequirement"/> class.
/// </summary>
/// <param name="queryStringName">Query string name from which to authorize values.</param>
public UserGroupRequirement(string queryStringName = "id") => QueryStringName = queryStringName;
/// <summary>
/// Gets the query string name from which to authorize values.
/// </summary>
public string QueryStringName { get; }
}
}