From 67c8637bea4cfcf132b242207883f1bf4afcab61 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 2 Feb 2021 17:00:17 +0100 Subject: [PATCH] Permissions simplified. --- .../Apps/AppSettingsSearchSource.cs | 4 +--- .../Assets/AssetsSearchSource.cs | 4 +--- .../Contents/BulkUpdateCommandMiddleware.cs | 4 +--- .../Contents/ContentsSearchSource.cs | 4 +--- .../Contents/DomainObject/Guards/GuardContent.cs | 4 +--- .../GraphQL/Types/Contents/ContentActions.cs | 6 +----- .../Contents/Queries/ContentQueryService.cs | 4 +--- backend/src/Squidex.Domain.Apps.Entities/Context.cs | 5 +++++ .../Schemas/SchemasSearchSource.cs | 4 +--- .../Identity/SquidexClaimsExtensions.cs | 5 +++++ backend/src/Squidex.Shared/Permissions.cs | 12 ++++++------ backend/src/Squidex.Web/ApiPermissionAttribute.cs | 4 +--- backend/src/Squidex.Web/Resources.cs | 6 ++---- .../Areas/Api/Controllers/Apps/AppsController.cs | 2 +- .../OrleansDashboardAuthenticationMiddleware.cs | 7 +------ .../Contents/BulkUpdateCommandMiddlewareTests.cs | 3 ++- .../Contents/GraphQL/GraphQLMutationTests.cs | 1 - .../Contents/MongoDb/ContentsQueryFixture.cs | 1 - .../Schemas/Indexes/SchemasIndexTests.cs | 8 ++++---- 19 files changed, 35 insertions(+), 53 deletions(-) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs index e171f81bf..412a8d662 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Apps/AppSettingsSearchSource.cs @@ -36,9 +36,7 @@ namespace Squidex.Domain.Apps.Entities.Apps { if (result.Count < MaxItems && term.Contains(query, StringComparison.OrdinalIgnoreCase)) { - var permission = Permissions.ForApp(permissionId, appId.Name); - - if (context.Permissions.Allows(permission)) + if (context.Allows(permissionId)) { var url = generate(appId); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsSearchSource.cs index 0a1f4c342..2c8765fcc 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Assets/AssetsSearchSource.cs @@ -34,9 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Assets { var result = new SearchResults(); - var permission = Permissions.ForApp(Permissions.AppAssetsRead, context.App.Name); - - if (context.Permissions.Allows(permission)) + if (context.Permissions.Allows(Permissions.AppAssetsRead, context.App.Name)) { var filter = ClrFilter.Contains("fileName", query); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs index aff2bef53..86477e789 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/BulkUpdateCommandMiddleware.cs @@ -262,9 +262,7 @@ namespace Squidex.Domain.Apps.Entities.Contents command.SchemaId = schema.NamedId(); } - var permission = Permissions.ForApp(permissionId, command.AppId.Name, command.SchemaId.Name); - - if (!task.Context.Permissions.Allows(permission)) + if (!task.Context.Allows(permissionId, command.SchemaId.Name)) { throw new DomainForbiddenException("Forbidden"); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs index 9fee30ee7..8f37de45f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentsSearchSource.cs @@ -105,9 +105,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private static bool HasPermission(Context context, string schemaName) { - var permission = Permissions.ForApp(Permissions.AppContentsReadOwn, context.App.Name, schemaName); - - return context.Permissions.Allows(permission); + return context.Permissions.Allows(Permissions.AppContentsReadOwn, context.App.Name, schemaName); } private static string FormatName(IEnrichedContentEntity content, string masterLanguage) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs index 5796817f6..e2f1c3fa3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/GuardContent.cs @@ -203,9 +203,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards return; } - var requiredPermission = Permissions.ForApp(permission, content.AppId.Name, content.SchemaId.Name); - - if (!command.User.Claims.Permissions().Allows(requiredPermission)) + if (!command.User.Allows(permission, content.AppId.Name, content.SchemaId.Name)) { throw new DomainForbiddenException(T.Get("common.errorNoPermission")); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs index 3a83227d2..3fcbeb31c 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/ContentActions.cs @@ -17,7 +17,6 @@ using Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Primitives; using Squidex.Infrastructure; using Squidex.Infrastructure.Json.Objects; using Squidex.Infrastructure.Translations; -using Squidex.Infrastructure.Validation; using Squidex.Shared; namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents @@ -430,10 +429,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types.Contents private static void CheckPermission(string permissionId, GraphQLExecutionContext context, NamedId schemaId) { - var requestContext = context.Context; - var requestPermission = Permissions.ForApp(permissionId, requestContext.App.Name, schemaId.Name); - - if (!requestContext.Permissions.Allows(requestPermission)) + if (!context.Context.Allows(permissionId, schemaId.Name)) { throw new DomainForbiddenException(T.Get("common.errorNoPermission")); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs index e9131c019..00ecbf884 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentQueryService.cs @@ -216,9 +216,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Queries private static bool HasPermission(Context context, ISchemaEntity schema, string permissionId) { - var permission = Permissions.ForApp(permissionId, context.App.Name, schema.SchemaDef.Name); - - return context.Permissions.Allows(permission); + return context.Permissions.Allows(permissionId, context.App.Name, schema.SchemaDef.Name); } private Task FindCoreAsync(Context context, DomainId id, ISchemaEntity schema) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Context.cs b/backend/src/Squidex.Domain.Apps.Entities/Context.cs index e35874636..04aed9c69 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Context.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Context.cs @@ -65,6 +65,11 @@ namespace Squidex.Domain.Apps.Entities return new Context(claimsPrincipal); } + public bool Allows(string permissionId, string schema = Permission.Any) + { + return Permissions.Allows(permissionId, App.Name, schema); + } + public Context Clone() { var clone = new Context(User, App); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs index bfb5beb67..1e47176c3 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/SchemasSearchSource.cs @@ -87,9 +87,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas private static bool HasPermission(Context context, NamedId schemaId) { - var permission = Permissions.ForApp(Permissions.AppContentsReadOwn, context.App.Name, schemaId.Name); - - return context.Permissions.Allows(permission); + return context.Allows(Permissions.AppContentsReadOwn, schemaId.Name); } } } diff --git a/backend/src/Squidex.Shared/Identity/SquidexClaimsExtensions.cs b/backend/src/Squidex.Shared/Identity/SquidexClaimsExtensions.cs index c2dbbd48e..7fa0c0a9d 100644 --- a/backend/src/Squidex.Shared/Identity/SquidexClaimsExtensions.cs +++ b/backend/src/Squidex.Shared/Identity/SquidexClaimsExtensions.cs @@ -22,6 +22,11 @@ namespace Squidex.Shared.Identity return new PermissionSet(user.GetClaims(SquidexClaimTypes.Permissions).Select(x => new Permission(x.Value))); } + public static bool Allows(this ClaimsPrincipal user, string id, string app = Permission.Any, string schema = Permission.Any) + { + return user.Claims.Permissions().Allows(id, app, schema); + } + public static bool IsHidden(this IEnumerable user) { return user.HasClaimValue(SquidexClaimTypes.Hidden, "true"); diff --git a/backend/src/Squidex.Shared/Permissions.cs b/backend/src/Squidex.Shared/Permissions.cs index 336f2cfdb..7873b9ad2 100644 --- a/backend/src/Squidex.Shared/Permissions.cs +++ b/backend/src/Squidex.Shared/Permissions.cs @@ -174,18 +174,18 @@ namespace Squidex.Shared } } - public static Permission ForApp(string id, string app = Permission.Any, string schema = Permission.Any) + public static bool Allows(this PermissionSet permissions, string id, string app = Permission.Any, string schema = Permission.Any) { - Guard.NotNull(id, nameof(id)); + var permission = ForApp(id, app, schema); - return new Permission(id.Replace("{app}", app ?? Permission.Any).Replace("{name}", schema ?? Permission.Any)); + return permissions.Allows(permission); } - public static PermissionSet ToAppPermissions(this PermissionSet permissions, string app) + public static Permission ForApp(string id, string app = Permission.Any, string schema = Permission.Any) { - var matching = permissions.Where(x => x.StartsWith($"squidex.apps.{app}")); + Guard.NotNull(id, nameof(id)); - return new PermissionSet(matching); + return new Permission(id.Replace("{app}", app ?? Permission.Any).Replace("{name}", schema ?? Permission.Any)); } public static string[] ToAppNames(this PermissionSet permissions) diff --git a/backend/src/Squidex.Web/ApiPermissionAttribute.cs b/backend/src/Squidex.Web/ApiPermissionAttribute.cs index 557958579..e486b335c 100644 --- a/backend/src/Squidex.Web/ApiPermissionAttribute.cs +++ b/backend/src/Squidex.Web/ApiPermissionAttribute.cs @@ -57,9 +57,7 @@ namespace Squidex.Web schema = Permission.Any; } - var permission = Permissions.ForApp(id, app, schema); - - if (permissions.Allows(permission)) + if (permissions.Allows(id, app, schema)) { hasPermission = true; break; diff --git a/backend/src/Squidex.Web/Resources.cs b/backend/src/Squidex.Web/Resources.cs index 3239fa710..a9ddc1393 100644 --- a/backend/src/Squidex.Web/Resources.cs +++ b/backend/src/Squidex.Web/Resources.cs @@ -175,8 +175,6 @@ namespace Squidex.Web public ApiController Controller { get; } - public PermissionSet Permissions => Context.Permissions; - public Context Context { get; set; } public Resources(ApiController controller) @@ -200,7 +198,7 @@ namespace Squidex.Web public bool Includes(Permission permission, PermissionSet? additional = null) { - return Permissions.Includes(permission) || additional?.Includes(permission) == true; + return Context.Permissions.Includes(permission) || additional?.Includes(permission) == true; } public bool IsAllowedForSchema(string id, string schema) @@ -232,7 +230,7 @@ namespace Squidex.Web var permission = P.ForApp(id, app, schema); - return Permissions.Allows(permission) || additional?.Allows(permission) == true; + return Context.Permissions.Allows(permission) || additional?.Allows(permission) == true; } private string? GetAppName() diff --git a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs index 65437462f..a17c8a965 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Apps/AppsController.cs @@ -76,7 +76,7 @@ namespace Squidex.Areas.Api.Controllers.Apps public async Task GetApps() { var userOrClientId = HttpContext.User.UserOrClientId()!; - var userPermissions = Resources.Permissions; + var userPermissions = Resources.Context.Permissions; var apps = await appProvider.GetUserAppsAsync(userOrClientId, userPermissions); diff --git a/backend/src/Squidex/Areas/OrleansDashboard/Middlewares/OrleansDashboardAuthenticationMiddleware.cs b/backend/src/Squidex/Areas/OrleansDashboard/Middlewares/OrleansDashboardAuthenticationMiddleware.cs index 5a871405f..476fbf1b8 100644 --- a/backend/src/Squidex/Areas/OrleansDashboard/Middlewares/OrleansDashboardAuthenticationMiddleware.cs +++ b/backend/src/Squidex/Areas/OrleansDashboard/Middlewares/OrleansDashboardAuthenticationMiddleware.cs @@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.Http; -using Squidex.Infrastructure.Security; using Squidex.Shared; using Squidex.Shared.Identity; @@ -18,8 +17,6 @@ namespace Squidex.Areas.OrleansDashboard.Middlewares { public sealed class OrleansDashboardAuthenticationMiddleware { - private static readonly Permission OrleansPermissions = new Permission(Permissions.AdminOrleans); - private readonly RequestDelegate next; public OrleansDashboardAuthenticationMiddleware(RequestDelegate next) @@ -33,9 +30,7 @@ namespace Squidex.Areas.OrleansDashboard.Middlewares if (authentication.Succeeded) { - var permisisons = authentication.Principal?.Claims.Permissions(); - - if (permisisons?.Allows(OrleansPermissions) == true) + if (authentication.Principal?.Allows(Permissions.AdminOrleans) == true) { await next(context); } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs index 731e7a0dd..3c865b065 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/BulkUpdateCommandMiddlewareTests.cs @@ -12,6 +12,7 @@ using FakeItEasy; using NodaTime; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Contents.Commands; +using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Infrastructure; using Squidex.Infrastructure.Commands; using Squidex.Infrastructure.Json.Objects; @@ -486,7 +487,7 @@ namespace Squidex.Domain.Apps.Entities.Contents claimsIdentity.AddClaim(new Claim(SquidexClaimTypes.Permissions, permission)); - var requestContext = new Context(claimsPrincipal); + var requestContext = new Context(claimsPrincipal, Mocks.App(appId)); A.CallTo(() => contextProvider.Context) .Returns(requestContext); diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs index 83cf76ed6..875fc4a86 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLMutationTests.cs @@ -10,7 +10,6 @@ using System.Threading.Tasks; using FakeItEasy; using GraphQL; using GraphQL.NewtonsoftJson; -using GraphQL.Types; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NodaTime; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs index 5f94553f1..3ec4e5238 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/MongoDb/ContentsQueryFixture.cs @@ -18,7 +18,6 @@ using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.TestHelpers; using Squidex.Domain.Apps.Entities.Apps; -using Squidex.Domain.Apps.Entities.Contents.Repositories; using Squidex.Domain.Apps.Entities.MongoDb.Contents; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Domain.Apps.Entities.TestHelpers; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs index 1ce40ef53..64b2fd38f 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Schemas/Indexes/SchemasIndexTests.cs @@ -247,7 +247,7 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes { var (_, schemaGrain) = SetupSchema(); - var command = new UpdateSchema { SchemaId = schemaId }; + var command = new UpdateSchema { SchemaId = schemaId, AppId = appId }; var context = new CommandContext(command, commandBus) @@ -262,13 +262,13 @@ namespace Squidex.Domain.Apps.Entities.Schemas.Indexes [Fact] public async Task Should_update_index_with_result_when_schema_is_updated() { - var (_, schemaGrain) = SetupSchema(); + var (schema, schemaGrain) = SetupSchema(); - var command = new UpdateSchema { SchemaId = schemaId }; + var command = new UpdateSchema { SchemaId = schemaId, AppId = appId }; var context = new CommandContext(command, commandBus) - .Complete(schemaGrain); + .Complete(schema); await sut.HandleAsync(context);