mirror of https://github.com/Squidex/squidex.git
56 changed files with 824 additions and 463 deletions
@ -0,0 +1,6 @@ |
|||
namespace Squidex.Domain.Apps.Core |
|||
{ |
|||
public sealed class DefaultPermissions |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,119 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Infrastructure; |
|||
using Squidex.Infrastructure.Security; |
|||
|
|||
namespace Squidex.Domain.Apps.Core |
|||
{ |
|||
public sealed class Permissions |
|||
{ |
|||
public const string ClaimType = "Permission"; |
|||
|
|||
public const string All = "squidex.*"; |
|||
|
|||
public const string Admin = "squidex.admin*"; |
|||
|
|||
public const string AdminRestore = "squidex.admin.restore"; |
|||
public const string AdminRestoreRead = "squidex.admin.restore.read"; |
|||
public const string AdminRestoreCreate = "squidex.admin.restore.create"; |
|||
|
|||
public const string AdminEvents = "squidex.admin.events"; |
|||
public const string AdminEventsRead = "squidex.admin.events.read"; |
|||
public const string AdminEventsManage = "squidex.admin.events.manage"; |
|||
|
|||
public const string AdminUsers = "squidex.admin.users"; |
|||
public const string AdminUsersRead = "squidex.admin.users.read"; |
|||
public const string AdminUsersCreate = "squidex.admin.users.create"; |
|||
public const string AdminUsersUpdate = "squidex.admin.users.update"; |
|||
public const string AdminUsersUnlock = "squidex.admin.users.unlock"; |
|||
public const string AdminUsersLock = "squidex.admin.users.lock"; |
|||
|
|||
public const string App = "squidex.apps.{app}"; |
|||
public const string AppDelete = "squidex.apps.{app}.delete"; |
|||
public const string AppCommon = "squidex.apps.{app}.common"; |
|||
|
|||
public const string AppClients = "squidex.apps.{app}.clients"; |
|||
public const string AppClientsRead = "squidex.apps.{app}.clients.read"; |
|||
public const string AppClientsCreate = "squidex.apps.{app}.clients.create"; |
|||
public const string AppClientsUpdate = "squidex.apps.{app}.clients.update"; |
|||
public const string AppClientsDelete = "squidex.apps.{app}.clients.delete"; |
|||
|
|||
public const string AppContributors = "squidex.apps.{app}.contributors"; |
|||
public const string AppContributorsRead = "squidex.apps.{app}.contributors.read"; |
|||
public const string AppContributorsAssign = "squidex.apps.{app}.contributors.assign"; |
|||
public const string AppContributorsRevoke = "squidex.apps.{app}.contributors.revoke"; |
|||
|
|||
public const string AppLanguages = "squidex.apps.{app}.languages"; |
|||
public const string AppLanguagesRead = "squidex.apps.{app}.languages.read"; |
|||
public const string AppLanguagesCreate = "squidex.apps.{app}.languages.create"; |
|||
public const string AppLanguagesUpdate = "squidex.apps.{app}.languages.update"; |
|||
public const string AppLanguagesDelete = "squidex.apps.{app}.languages.delete"; |
|||
|
|||
public const string AppPatterns = "squidex.apps.{app}.patterns"; |
|||
public const string AppPatternsRead = "squidex.apps.{app}.patterns.read"; |
|||
public const string AppPatternsCreate = "squidex.apps.{app}.patterns.create"; |
|||
public const string AppPatternsUpdate = "squidex.apps.{app}.patterns.update"; |
|||
public const string AppPatternsDelete = "squidex.apps.{app}.patterns.delete"; |
|||
|
|||
public const string AppBackups = "squidex.apps.{app}.backups"; |
|||
public const string AppBackupsRead = "squidex.apps.{app}.backups.read"; |
|||
public const string AppBackupsCreate = "squidex.apps.{app}.backups.create"; |
|||
public const string AppBackupsDelete = "squidex.apps.{app}.backups.delete"; |
|||
|
|||
public const string AppPlans = "squidex.apps.{app}.plans"; |
|||
public const string AppPlansRead = "squidex.apps.{app}.plans.read"; |
|||
public const string AppPlansChange = "squidex.apps.{app}.plans.change"; |
|||
|
|||
public const string AppAssets = "squidex.apps.{app}.assets"; |
|||
public const string AppAssetsRead = "squidex.apps.{app}.assets.read"; |
|||
public const string AppAssetsCreate = "squidex.apps.{app}.assets.create"; |
|||
public const string AppAssetsUpdate = "squidex.apps.{app}.assets.update"; |
|||
public const string AppAssetsDelete = "squidex.apps.{app}.assets.delete"; |
|||
|
|||
public const string AppRules = "squidex.apps.{app}.rules"; |
|||
public const string AppRulesRead = "squidex.apps.{app}.rules.read"; |
|||
public const string AppRulesCreate = "squidex.apps.{app}.rules.create"; |
|||
public const string AppRulesUpdate = "squidex.apps.{app}.rules.update"; |
|||
public const string AppRulesDisable = "squidex.apps.{app}.rules.disable"; |
|||
public const string AppRulesDelete = "squidex.apps.{app}.rules.delete"; |
|||
|
|||
public const string AppSchemas = "squidex.apps.{app}.schemas.{name}"; |
|||
public const string AppSchemasRead = "squidex.apps.{app}.schemas.{name}.read"; |
|||
public const string AppSchemasCreate = "squidex.apps.{app}.schemas.{name}.create"; |
|||
public const string AppSchemasUpdate = "squidex.apps.{app}.schemas.{name}.update"; |
|||
public const string AppSchemasScripts = "squidex.apps.{app}.schemas.{name}.scripts"; |
|||
public const string AppSchemasPublish = "squidex.apps.{app}.schemas.{name}.publish"; |
|||
public const string AppSchemasDelete = "squidex.apps.{app}.schemas.{name}.delete"; |
|||
|
|||
public const string AppContents = "squidex.apps.{app}.contents.{name}"; |
|||
public const string AppContentsRead = "squidex.apps.{app}.contents.{name}.read"; |
|||
public const string AppContentsGraphQL = "squidex.apps.{app}.contents.{name}.graphql"; |
|||
public const string AppContentsCreate = "squidex.apps.{app}.contents.{name}.create"; |
|||
public const string AppContentsUpdate = "squidex.apps.{app}.contents.{name}.update"; |
|||
public const string AppContentsDiscard = "squidex.apps.{app}.contents.{name}.discard"; |
|||
public const string AppContentsArchive = "squidex.apps.{app}.contents.{name}.archive"; |
|||
public const string AppContentsRestore = "squidex.apps.{app}.contents.{name}.restore"; |
|||
public const string AppContentsPublish = "squidex.apps.{app}.contents.{name}.publish"; |
|||
public const string AppContentsUnpublish = "squidex.apps.{app}.contents.{name}.unpublish"; |
|||
public const string AppContentsDelete = "squidex.apps.{app}.contents.{name}.delete"; |
|||
|
|||
public static Permission ForApp(string id, string app = "*") |
|||
{ |
|||
Guard.NotNull(id, nameof(id)); |
|||
|
|||
return new Permission(id.Replace("{app}", app ?? "*")); |
|||
} |
|||
|
|||
public static Permission ForSchema(string id, string app = "*", string schema = "*") |
|||
{ |
|||
Guard.NotNull(id, nameof(id)); |
|||
|
|||
return new Permission(id.Replace("{app}", app ?? "*").Replace("{name}", schema ?? "*")); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
|
|||
namespace Squidex.Infrastructure.Security |
|||
{ |
|||
public sealed class Permission : IComparable<Permission>, IEquatable<Permission> |
|||
{ |
|||
private const string Any = "*"; |
|||
private static readonly char[] Separators = { '.' }; |
|||
private readonly string description; |
|||
private readonly string id; |
|||
private readonly string[] idParts; |
|||
|
|||
public string Id |
|||
{ |
|||
get { return id; } |
|||
} |
|||
|
|||
public string Description |
|||
{ |
|||
get { return description; } |
|||
} |
|||
|
|||
public Permission(string id, string description = null) |
|||
{ |
|||
Guard.NotNullOrEmpty(id, nameof(id)); |
|||
|
|||
this.description = description; |
|||
|
|||
this.id = id; |
|||
this.idParts = id.Split(Separators, StringSplitOptions.RemoveEmptyEntries); |
|||
} |
|||
|
|||
public bool GivesPermissionTo(Permission permission) |
|||
{ |
|||
if (permission == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
if (idParts.Length > permission.idParts.Length) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
for (var i = 0; i < idParts.Length; i++) |
|||
{ |
|||
var lhs = idParts[i]; |
|||
var rhs = permission.idParts[i]; |
|||
|
|||
if (!string.Equals(lhs, Any, StringComparison.OrdinalIgnoreCase) && |
|||
!string.Equals(lhs, rhs, StringComparison.OrdinalIgnoreCase)) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
|
|||
public override bool Equals(object obj) |
|||
{ |
|||
return Equals(obj as Permission); |
|||
} |
|||
|
|||
public bool Equals(Permission other) |
|||
{ |
|||
return other != null && string.Equals(id, other.id, StringComparison.OrdinalIgnoreCase); |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
return id.GetHashCode(); |
|||
} |
|||
|
|||
public override string ToString() |
|||
{ |
|||
return id; |
|||
} |
|||
|
|||
public int CompareTo(Permission other) |
|||
{ |
|||
return other == null ? -1 : string.Compare(id, other.id, StringComparison.Ordinal); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace Squidex.Infrastructure.Security |
|||
{ |
|||
public sealed class PermissionSet : IReadOnlyCollection<Permission> |
|||
{ |
|||
public static readonly PermissionSet Empty = new PermissionSet(); |
|||
|
|||
private readonly List<Permission> permissions; |
|||
|
|||
public int Count |
|||
{ |
|||
get { return permissions.Count; } |
|||
} |
|||
|
|||
public PermissionSet(IEnumerable<Permission> permissions) |
|||
{ |
|||
Guard.NotNull(permissions, nameof(permissions)); |
|||
|
|||
this.permissions = permissions.ToList(); |
|||
} |
|||
|
|||
public PermissionSet(params Permission[] permissions) |
|||
{ |
|||
Guard.NotNull(permissions, nameof(permissions)); |
|||
|
|||
this.permissions = permissions.ToList(); |
|||
} |
|||
|
|||
public bool GivesPermissionTo(Permission other) |
|||
{ |
|||
if (other == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
foreach (var permission in permissions) |
|||
{ |
|||
if (permission.GivesPermissionTo(other)) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public IEnumerator<Permission> GetEnumerator() |
|||
{ |
|||
return permissions.GetEnumerator(); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return permissions.GetEnumerator(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,20 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using IdentityServer4.AccessTokenValidation; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public class ApiAuthorizeAttribute : AuthorizeAttribute |
|||
{ |
|||
public ApiAuthorizeAttribute() |
|||
{ |
|||
AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using IdentityServer4.AccessTokenValidation; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Squidex.Infrastructure.Security; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class ApiPermissionAttribute : AuthorizeAttribute, IAsyncActionFilter |
|||
{ |
|||
private readonly string permissionId; |
|||
|
|||
public ApiPermissionAttribute(string id = null) |
|||
{ |
|||
AuthenticationSchemes = IdentityServerAuthenticationDefaults.AuthenticationScheme; |
|||
|
|||
permissionId = id; |
|||
} |
|||
|
|||
public Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) |
|||
{ |
|||
if (permissionId != null) |
|||
{ |
|||
var id = permissionId; |
|||
|
|||
foreach (var routeParam in context.RouteData.Values) |
|||
{ |
|||
id = id.Replace($"{{{routeParam.Key}}}", routeParam.Value?.ToString()); |
|||
} |
|||
|
|||
var set = new PermissionSet( |
|||
context.HttpContext.User.FindAll("Permission") |
|||
.Select(x => x.Value) |
|||
.Select(x => new Permission(x))); |
|||
|
|||
if (!set.GivesPermissionTo(new Permission(id))) |
|||
{ |
|||
// context.Result = new StatusCodeResult(403);
|
|||
} |
|||
} |
|||
|
|||
return next(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Microsoft.AspNetCore.Mvc; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class AppApiAttribute : ServiceFilterAttribute |
|||
{ |
|||
public AppApiAttribute() |
|||
: base(typeof(AppApiFilter)) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,55 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Squidex.Domain.Apps.Entities; |
|||
using Squidex.Domain.Apps.Entities.Apps; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class AppApiFilter : IAsyncActionFilter |
|||
{ |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public class AppFeature : IAppFeature |
|||
{ |
|||
public IAppEntity App { get; } |
|||
|
|||
public AppFeature(IAppEntity app) |
|||
{ |
|||
App = app; |
|||
} |
|||
} |
|||
|
|||
public AppApiFilter(IAppProvider appProvider) |
|||
{ |
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) |
|||
{ |
|||
var appName = context.RouteData.Values["app"]?.ToString(); |
|||
|
|||
if (!string.IsNullOrWhiteSpace(appName)) |
|||
{ |
|||
var app = await appProvider.GetAppAsync(appName); |
|||
|
|||
if (app == null) |
|||
{ |
|||
context.Result = new NotFoundResult(); |
|||
return; |
|||
} |
|||
|
|||
context.HttpContext.Features.Set<IAppFeature>(new AppFeature(app)); |
|||
} |
|||
|
|||
await next(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,106 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Security.Claims; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Squidex.Domain.Apps.Core.Apps; |
|||
using Squidex.Domain.Apps.Entities.Apps; |
|||
using Squidex.Infrastructure.Security; |
|||
using Squidex.Shared.Identity; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public abstract class AppPermissionAttribute : ActionFilterAttribute |
|||
{ |
|||
private readonly AppPermission requestedPermission; |
|||
|
|||
protected AppPermissionAttribute(AppPermission requestedPermission) |
|||
{ |
|||
this.requestedPermission = requestedPermission; |
|||
} |
|||
|
|||
public override void OnActionExecuting(ActionExecutingContext context) |
|||
{ |
|||
var app = context.HttpContext.Features.Get<IAppFeature>()?.App; |
|||
|
|||
if (app != null) |
|||
{ |
|||
var user = context.HttpContext.User; |
|||
|
|||
var permission = |
|||
FindByOpenIdSubject(app, user) ?? |
|||
FindByOpenIdClient(app, user); |
|||
|
|||
if (permission == null) |
|||
{ |
|||
context.Result = new NotFoundResult(); |
|||
return; |
|||
} |
|||
|
|||
if (permission.Value > requestedPermission) |
|||
{ |
|||
context.Result = new StatusCodeResult(403); |
|||
return; |
|||
} |
|||
|
|||
var defaultIdentity = context.HttpContext.User.Identities.First(); |
|||
|
|||
var additionalRoles = new List<string> |
|||
{ |
|||
SquidexRoles.AppReader |
|||
}; |
|||
|
|||
if (permission.Value <= AppPermission.Editor) |
|||
{ |
|||
additionalRoles.Add(SquidexRoles.AppEditor); |
|||
} |
|||
|
|||
if (permission.Value <= AppPermission.Developer) |
|||
{ |
|||
additionalRoles.Add(SquidexRoles.AppDeveloper); |
|||
} |
|||
|
|||
if (permission.Value <= AppPermission.Owner) |
|||
{ |
|||
additionalRoles.Add(SquidexRoles.AppOwner); |
|||
} |
|||
|
|||
foreach (var role in additionalRoles) |
|||
{ |
|||
defaultIdentity.AddClaim(new Claim(defaultIdentity.RoleClaimType, role)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static AppPermission? FindByOpenIdClient(IAppEntity app, ClaimsPrincipal user) |
|||
{ |
|||
var clientId = user.GetClientId(); |
|||
|
|||
if (clientId != null && app.Clients.TryGetValue(clientId, out var client)) |
|||
{ |
|||
return client.Permission.ToAppPermission(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
private static AppPermission? FindByOpenIdSubject(IAppEntity app, ClaimsPrincipal user) |
|||
{ |
|||
var subjectId = user.FindFirst(OpenIdClaims.Subject)?.Value; |
|||
|
|||
if (subjectId != null && app.Contributors.TryGetValue(subjectId, out var permission)) |
|||
{ |
|||
return permission.ToAppPermission(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Linq; |
|||
using System.Security.Claims; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.AspNetCore.Mvc.Filters; |
|||
using Squidex.Domain.Apps.Core.Apps; |
|||
using Squidex.Domain.Apps.Entities; |
|||
using Squidex.Domain.Apps.Entities.Apps; |
|||
using Squidex.Infrastructure.Security; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class AppResolverFilter : IAsyncActionFilter |
|||
{ |
|||
private readonly IAppProvider appProvider; |
|||
|
|||
public class AppFeature : IAppFeature |
|||
{ |
|||
public IAppEntity App { get; } |
|||
|
|||
public AppFeature(IAppEntity app) |
|||
{ |
|||
App = app; |
|||
} |
|||
} |
|||
|
|||
public AppResolverFilter(IAppProvider appProvider) |
|||
{ |
|||
this.appProvider = appProvider; |
|||
} |
|||
|
|||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) |
|||
{ |
|||
var appName = context.RouteData.Values["app"]?.ToString(); |
|||
|
|||
if (!string.IsNullOrWhiteSpace(appName)) |
|||
{ |
|||
var app = await appProvider.GetAppAsync(appName); |
|||
|
|||
if (app == null) |
|||
{ |
|||
context.Result = new NotFoundResult(); |
|||
return; |
|||
} |
|||
|
|||
var user = context.HttpContext.User; |
|||
|
|||
var permissions = |
|||
FindByOpenIdSubject(app, user) ?? |
|||
FindByOpenIdClient(app, user); |
|||
|
|||
if (permissions.Count == 0) |
|||
{ |
|||
context.Result = new NotFoundResult(); |
|||
return; |
|||
} |
|||
|
|||
var identity = user.Identities.First(); |
|||
|
|||
foreach (var permission in permissions) |
|||
{ |
|||
identity.AddClaim(new Claim("Permission", permission.Id)); |
|||
} |
|||
|
|||
context.HttpContext.Features.Set<IAppFeature>(new AppFeature(app)); |
|||
} |
|||
|
|||
await next(); |
|||
} |
|||
|
|||
private static PermissionSet FindByOpenIdClient(IAppEntity app, ClaimsPrincipal user) |
|||
{ |
|||
var clientId = user.GetClientId(); |
|||
|
|||
if (clientId != null && app.Clients.TryGetValue(clientId, out var client)) |
|||
{ |
|||
return client.Permission.ToPermissions(app.Name); |
|||
} |
|||
|
|||
return PermissionSet.Empty; |
|||
} |
|||
|
|||
private static PermissionSet FindByOpenIdSubject(IAppEntity app, ClaimsPrincipal user) |
|||
{ |
|||
var subjectId = user.FindFirst(OpenIdClaims.Subject)?.Value; |
|||
|
|||
if (subjectId != null && app.Contributors.TryGetValue(subjectId, out var permission)) |
|||
{ |
|||
return permission.ToPermissions(app.Name); |
|||
} |
|||
|
|||
return PermissionSet.Empty; |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Shared.Identity; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class MustBeAdministratorAttribute : ApiAuthorizeAttribute |
|||
{ |
|||
public MustBeAdministratorAttribute() |
|||
{ |
|||
Roles = SquidexRoles.Administrator; |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Domain.Apps.Core.Apps; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class MustBeAppDeveloperAttribute : AppPermissionAttribute |
|||
{ |
|||
public MustBeAppDeveloperAttribute() |
|||
: base(AppPermission.Developer) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Domain.Apps.Core.Apps; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class MustBeAppEditorAttribute : AppPermissionAttribute |
|||
{ |
|||
public MustBeAppEditorAttribute() |
|||
: base(AppPermission.Editor) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Domain.Apps.Core.Apps; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class MustBeAppOwnerAttribute : AppPermissionAttribute |
|||
{ |
|||
public MustBeAppOwnerAttribute() |
|||
: base(AppPermission.Owner) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -1,19 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using Squidex.Domain.Apps.Core.Apps; |
|||
|
|||
namespace Squidex.Pipeline |
|||
{ |
|||
public sealed class MustBeAppReaderAttribute : AppPermissionAttribute |
|||
{ |
|||
public MustBeAppReaderAttribute() |
|||
: base(AppPermission.Reader) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Infrastructure.Security |
|||
{ |
|||
public sealed class PermissionSetTests |
|||
{ |
|||
[Fact] |
|||
public void Should_provide_collection_features() |
|||
{ |
|||
var source = new List<Permission> |
|||
{ |
|||
new Permission("c"), |
|||
new Permission("b"), |
|||
new Permission("a") |
|||
}; |
|||
|
|||
var sut = new PermissionSet(source); |
|||
|
|||
Assert.Equal(sut.ToList(), source); |
|||
Assert.Equal(((IEnumerable)sut).OfType<Permission>().ToList(), source); |
|||
|
|||
Assert.Equal(3, source.Count); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_true_if_any_permission_gives_permission_to_request() |
|||
{ |
|||
var sut = new PermissionSet( |
|||
new Permission("app.contents"), |
|||
new Permission("app.assets")); |
|||
|
|||
Assert.True(sut.GivesPermissionTo(new Permission("app.contents"))); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_false_if_none_permission_gives_permission_to_request() |
|||
{ |
|||
var sut = new PermissionSet( |
|||
new Permission("app.contents"), |
|||
new Permission("app.assets")); |
|||
|
|||
Assert.False(sut.GivesPermissionTo(new Permission("app.schemas"))); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_false_if_permission_to_request_is_null() |
|||
{ |
|||
var sut = new PermissionSet( |
|||
new Permission("app.contents"), |
|||
new Permission("app.assets")); |
|||
|
|||
Assert.False(sut.GivesPermissionTo(null)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,138 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Infrastructure.Security |
|||
{ |
|||
public class PermissionTests |
|||
{ |
|||
[Fact] |
|||
public void Should_generate_permissions() |
|||
{ |
|||
var sut = new Permission("app.contents", "App Contents"); |
|||
|
|||
Assert.Equal("app.contents", sut.ToString()); |
|||
Assert.Equal("app.contents", sut.Id); |
|||
Assert.Equal("App Contents", sut.Description); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_true_if_given_and_requested_permission_have_wildcards() |
|||
{ |
|||
var g = new Permission("app.*"); |
|||
var r = new Permission("app.*"); |
|||
|
|||
Assert.True(g.GivesPermissionTo(r)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_true_if_given_permission_equals_requested_permission() |
|||
{ |
|||
var g = new Permission("app.contents"); |
|||
var r = new Permission("app.contents"); |
|||
|
|||
Assert.True(g.GivesPermissionTo(r)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_true_if_given_permission_is_parent_of_requested_permission() |
|||
{ |
|||
var g = new Permission("app"); |
|||
var r = new Permission("app.contents"); |
|||
|
|||
Assert.True(g.GivesPermissionTo(r)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_true_if_given_permission_has_wildcard_for_requested_permission() |
|||
{ |
|||
var g = new Permission("app.*"); |
|||
var r = new Permission("app.contents"); |
|||
|
|||
Assert.True(g.GivesPermissionTo(r)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_false_if_given_permission_not_equals_requested_permission() |
|||
{ |
|||
var g = new Permission("app.contents"); |
|||
var r = new Permission("app.assets"); |
|||
|
|||
Assert.False(g.GivesPermissionTo(r)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_false_if_given_permission_is_child_of_requested_permission() |
|||
{ |
|||
var g = new Permission("app.contents"); |
|||
var r = new Permission("app"); |
|||
|
|||
Assert.False(g.GivesPermissionTo(r)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_false_if_given_permission_has_no_wildcard_but_requested_has() |
|||
{ |
|||
var g = new Permission("app.contents"); |
|||
var r = new Permission("app.*"); |
|||
|
|||
Assert.False(g.GivesPermissionTo(r)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_false_if_given_requested_permission_is_null() |
|||
{ |
|||
var g = new Permission("app.contents"); |
|||
|
|||
Assert.False(g.GivesPermissionTo(null)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_make_correct_object_equal_comparisons() |
|||
{ |
|||
object permission1a = new Permission("app.1"); |
|||
object permission1b = new Permission("app.1"); |
|||
object permission2a = new Permission("app.2"); |
|||
|
|||
Assert.True(permission1a.Equals(permission1b)); |
|||
|
|||
Assert.False(permission1a.Equals(permission2a)); |
|||
Assert.False(permission1b.Equals(permission2a)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_provide_correct_hash_codes() |
|||
{ |
|||
var permission1a = new Permission("app.1"); |
|||
var permission1b = new Permission("app.1"); |
|||
var permission2a = new Permission("app.2"); |
|||
|
|||
Assert.Equal(permission1a.GetHashCode(), permission1b.GetHashCode()); |
|||
|
|||
Assert.NotEqual(permission1a.GetHashCode(), permission2a.GetHashCode()); |
|||
Assert.NotEqual(permission1b.GetHashCode(), permission2a.GetHashCode()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_sort_by_name() |
|||
{ |
|||
var source = new List<Permission> |
|||
{ |
|||
new Permission("c"), |
|||
new Permission("b"), |
|||
new Permission("a") |
|||
}; |
|||
|
|||
var sorted = source.OrderBy(x => x).ToList(); |
|||
|
|||
Assert.Equal(new List<Permission> { source[2], source[1], source[0] }, sorted); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue