compose available permissions in zero builder and output them in role detail

This commit is contained in:
2020-04-27 15:49:14 +02:00
parent c02b721354
commit ef692b593b
18 changed files with 288 additions and 87 deletions
+30
View File
@@ -0,0 +1,30 @@
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using zero.Core.Identity;
namespace zero.Core.Api
{
public class PermissionsApi : IPermissionsApi
{
protected ZeroOptions Options { get; set; }
public PermissionsApi (IOptionsMonitor<ZeroOptions> options)
{
Options = options.CurrentValue;
}
/// <inheritdoc />
//public IList<PermissionCollection> GetPermissions()
//{
//}
}
public interface IPermissionsApi
{
}
}
+1 -1
View File
@@ -74,7 +74,7 @@ namespace zero.Core.Api
{
return Principal.Claims
.Where(claim => claim.Type == Constants.Auth.Claims.Permission && (prefix == null || claim.Value.StartsWith(prefix)))
.Select(claim => new Permission(claim, prefix))
.Select(claim => Permission.FromClaim(claim, prefix))
.ToList();
}
+3 -1
View File
@@ -38,7 +38,7 @@
public const string Settings = "settings";
}
public static class SettingsAreas
public static class Settings
{
public const string Updates = "updates";
public const string Applications = "applications";
@@ -46,6 +46,8 @@
public const string Translations = "translations";
public const string Countries = "countries";
public const string Logging = "logs";
public const string Plugins = "plugins";
public const string CreatePlugin = "createplugin";
}
}
}
+84 -28
View File
@@ -7,63 +7,119 @@ namespace zero.Core.Identity
{
public class Permission
{
/// <summary>
/// Full key (stored in left part claim value) of the permission
/// </summary>
public string Key { get; set; }
/// <summary>
/// Normalized key with optionally removed prefix
/// </summary>
public string NormalizedKey { get; set; }
/// <summary>
/// Value of the permission (boolean, read/write, ...). Stored in right part of claim value
/// </summary>
public string Value { get; set; }
public bool CanRead => Value == PermissionsValue.Read || Value == PermissionsValue.Write;
/// <summary>
/// Title of this permission for output
/// </summary>
public string Label { get; set; }
public bool CanWrite => Value == PermissionsValue.Write;
/// <summary>
/// Optional description text
/// </summary>
public string Description { get; set; }
public bool IsTrue => Value == PermissionsValue.True;
public bool IsFalse => Value == PermissionsValue.False;
/// <summary>
/// Datatype of the value
/// </summary>
public PermissionValueType ValueType { get; set; }
public Permission() { }
public Permission(Claim claim, string prefixToRemove = null) : this(claim.Value, prefixToRemove) { }
public Permission(string claimValue, string prefixToRemove = null)
public Permission(string key, string value, PermissionValueType valueType = PermissionValueType.ReadWrite)
{
string[] valueParts = claimValue.Split(':');
Key = key;
Value = value;
ValueType = valueType;
}
Key = valueParts[0];
NormalizedKey = Key;
Value = valueParts.Length > 1 ? valueParts[1] : null;
if (!prefixToRemove.IsNullOrEmpty())
{
NormalizedKey = valueParts[0].TrimStart(prefixToRemove);
}
public Permission(string key, string label, string description, PermissionValueType valueType = PermissionValueType.ReadWrite)
{
Key = key;
Label = label;
Description = description;
ValueType = valueType;
}
/// <summary>
/// Whether the value is read or write
/// </summary>
public bool CanRead => Value == PermissionsValue.Read || Value == PermissionsValue.Write;
/// <summary>
/// Whether the value is write
/// </summary>
public bool CanWrite => Value == PermissionsValue.Write;
/// <summary>
/// Whether the value is true
/// </summary>
public bool IsTrue => Value == PermissionsValue.True;
/// <summary>
/// Whether the value is false
/// </summary>
public bool IsFalse => Value == PermissionsValue.False;
/// <summary>
/// Whether a resource (with authorization based on the key) can be read by any of the given permisssions
/// </summary>
public static bool CanReadKey(IEnumerable<Permission> permissions, string key, bool isNormalized = false)
{
Permission permission = permissions.FirstOrDefault(p => isNormalized ? p.NormalizedKey == key : p.Key == key);
if (permission == null)
{
return false;
}
return permission.CanRead;
return permission?.CanRead ?? false;
}
/// <summary>
/// Whether a resource (with authorization based on the key) can be written to by any of the given permisssions
/// </summary>
public static bool CanWriteKey(IEnumerable<Permission> permissions, string key, bool isNormalized = false)
{
Permission permission = permissions.FirstOrDefault(p => isNormalized ? p.NormalizedKey == key : p.Key == key);
return permission?.CanWrite ?? false;
}
if (permission == null)
/// <summary>
/// Create a permission from a claim
/// </summary>
public static Permission FromClaim(Claim claim, string prefixToRemove = null)
{
return FromClaim(claim.Value, prefixToRemove);
}
/// <summary>
/// Create a permission from a claim
/// </summary>
public static Permission FromClaim(string claimValue, string prefixToRemove = null)
{
Permission permission = new Permission();
string[] valueParts = claimValue.Split(':');
permission.Key = valueParts[0];
permission.NormalizedKey = permission.Key;
permission.Value = valueParts.Length > 1 ? valueParts[1] : null;
if (!prefixToRemove.IsNullOrEmpty())
{
return false;
permission.NormalizedKey = valueParts[0].TrimStart(prefixToRemove);
}
return permission.CanWrite;
return permission;
}
}
}
@@ -0,0 +1,22 @@
using System.Collections.Generic;
namespace zero.Core.Identity
{
public class PermissionCollection
{
/// <summary>
/// Name of the group
/// </summary>
public string Label { get; set; }
/// <summary>
/// Optional description text
/// </summary>
public string Description { get; set; }
/// <summary>
/// Individual permissions (stored as claims on the user identity)
/// </summary>
public IList<Permission> Items { get; set; } = new List<Permission>();
}
}
+18
View File
@@ -0,0 +1,18 @@
namespace zero.Core.Identity
{
public enum PermissionValueType
{
/// <summary>
/// True or false
/// </summary>
Boolean = 0,
/// <summary>
/// Read, write or none
/// </summary>
ReadWrite = 1,
/// <summary>
/// Simple text string
/// </summary>
String = 2
}
}
+8 -6
View File
@@ -12,12 +12,14 @@
public struct Settings
{
public const string PREFIX = "settings.area.";
public const string Updates = PREFIX + Constants.SettingsAreas.Updates;
public const string Applications = PREFIX + Constants.SettingsAreas.Applications;
public const string Users = PREFIX + Constants.SettingsAreas.Users;
public const string Translations = PREFIX + Constants.SettingsAreas.Translations;
public const string Countries = PREFIX + Constants.SettingsAreas.Countries;
public const string Logging = PREFIX + Constants.SettingsAreas.Logging;
public const string Updates = PREFIX + Constants.Settings.Updates;
public const string Applications = PREFIX + Constants.Settings.Applications;
public const string Users = PREFIX + Constants.Settings.Users;
public const string Translations = PREFIX + Constants.Settings.Translations;
public const string Countries = PREFIX + Constants.Settings.Countries;
public const string Logging = PREFIX + Constants.Settings.Logging;
public const string Plugins = PREFIX + Constants.Settings.Plugins;
public const string CreatePlugin = PREFIX + Constants.Settings.CreatePlugin;
}
@@ -83,12 +83,9 @@ namespace zero.Core.Identity
// do not run this filter if it is overridden
if (siblingFilters.Length > 1 && currentIndex < siblingFilters.Length - 1)
{
Console.WriteLine("skip " + Permission + ": " + String.Join(", ", PermissionValues));
return;
}
Console.WriteLine("run " + Permission + ": " + String.Join(", ", PermissionValues));
ClaimsPrincipal user = context.HttpContext.User;
bool isAuthenticated = user.Identity.IsAuthenticated;
+9
View File
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using zero.Core.Entities;
using zero.Core.Identity;
namespace zero.Core
{
@@ -10,5 +11,13 @@ namespace zero.Core
public SectionCollection Sections { get; private set; } = new SectionCollection();
public IList<SettingsGroup> SettingsAreas { get; private set; } = new List<SettingsGroup>();
public ZeroAuthorizationOptions Authorization { get; private set; } = new ZeroAuthorizationOptions();
}
public class ZeroAuthorizationOptions
{
public IList<PermissionCollection> Permissions { get; private set; } = new List<PermissionCollection>();
}
}
+14 -25
View File
@@ -26,17 +26,13 @@
</ui-property>
</div>
<div class="ui-box">
<h2 class="ui-headline" v-localize="'@permission.sections'"></h2>
<ui-property class="role-permission-toggle" v-for="section in permissions.sections" :label="section.name">
<ui-toggle v-model="section.toggled" />
</ui-property>
</div>
<div class="ui-box">
<h2 class="ui-headline" v-localize="'@permission.settings'"></h2>
<ui-property class="role-permission-toggle" v-for="setting in permissions.settings" :label="setting.name">
<ui-toggle v-model="setting.toggled" />
<div v-for="permissionCollection in permissions" class="ui-box">
<h2 class="ui-headline">
{{ permissionCollection.label | localize }}
<span v-if="permissionCollection.description" class="-minor"><br>{{ permissionCollection.description | localize }}</span>
</h2>
<ui-property v-for="permission in permissionCollection.items" class="role-permission-toggle" :label="permission.label" :description="permission.description">
<ui-toggle v-model="permission.toggled" />
</ui-property>
</div>
</div>
@@ -70,10 +66,7 @@
name: null,
email: null
},
permissions: {
sections: [],
settings: []
}
permissions: []
}),
created()
@@ -83,16 +76,6 @@
icon: 'fth-trash',
action: this.onDelete
});
this.permissions.sections = zero.sections;
zero.settingsAreas.forEach(area =>
{
area.items.forEach(item =>
{
this.permissions.settings.push(item);
});
})
},
@@ -110,6 +93,12 @@
{
this.model = response;
});
UserRolesApi.getAllPermissions().then(response =>
{
console.info(response);
this.permissions = response;
});
},
onSubmit(form)
+7 -1
View File
@@ -12,5 +12,11 @@ export default {
getAll()
{
return Axios.get('userRoles/getAll').then(res => Promise.resolve(res.data));
}
},
// get all permissions
getAllPermissions()
{
return Axios.get('userRoles/getAllPermissions').then(res => Promise.resolve(res.data));
},
};
+1 -1
View File
@@ -5,7 +5,7 @@
<template v-slot:button>
<ui-button type="light" label="Actions" caret="down" />
</template>
<ui-dropdown-list :items="actions" :action="actionSelected" />
<ui-dropdown-list v-model="actions" :action="actionSelected" />
</ui-dropdown>
<ui-button type="light" label="Preview" icon="fth-eye" />
<ui-button label="Save" />
+15 -1
View File
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using zero.Core;
using zero.Core.Api;
@@ -15,9 +16,13 @@ namespace zero.Web.Controllers
{
private IUserRolesApi Api { get; set; }
public UserRolesController(IZeroConfiguration config, IUserRolesApi api, IMapper mapper, IToken token) : base(config, mapper, token)
private ZeroOptions Options { get; set; }
public UserRolesController(IZeroConfiguration config, IUserRolesApi api, IMapper mapper, IToken token, IOptionsMonitor<ZeroOptions> options) : base(config, mapper, token)
{
Api = api;
Options = options.CurrentValue;
}
@@ -38,5 +43,14 @@ namespace zero.Web.Controllers
{
return As<UserRole, UserRoleListModel>(await Api.GetAll());
}
/// <summary>
/// Get all permissions for selection
/// </summary>
public IActionResult GetAllPermissions()
{
return Json(Options.Authorization.Permissions);
}
}
}
+14 -1
View File
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using zero.Core;
using zero.Core.Api;
@@ -14,9 +15,12 @@ namespace zero.Web.Controllers
{
private IUserApi Api { get; set; }
public UsersController(IZeroConfiguration config, IUserApi api, IMapper mapper, IToken token) : base(config, mapper, token)
private ZeroOptions Options { get; set; }
public UsersController(IZeroConfiguration config, IUserApi api, IMapper mapper, IToken token, IOptionsMonitor<ZeroOptions> options) : base(config, mapper, token)
{
Api = api;
Options = options.CurrentValue;
}
@@ -36,5 +40,14 @@ namespace zero.Web.Controllers
{
return As<User, UserListModel>(await Api.GetByQuery(query, "zero.applications.1-A"));
}
/// <summary>
/// Get all permissions for selection
/// </summary>
public IActionResult GetAllPermissions()
{
return Json(Options.Authorization.Permissions);
}
}
}
@@ -80,7 +80,8 @@
"system": {
"updates": {
"name": "Updates",
"text": "Version {zero_version}"
"text": "Version {zero_version}",
"text_default": "Update current zero version"
},
"applications": {
"name": "Applications",
@@ -105,8 +106,9 @@
},
"plugins": {
"installed": {
"name": "Installed",
"text": "{plugin_count} installed plugin(s)"
"name": "Installed plugins",
"text": "{plugin_count} installed plugin(s)",
"text_default": "Manage and install plugins"
},
"create": {
"name": "Create a plugin",
@@ -147,8 +149,12 @@
},
"permission": {
"sections": "Sections",
"settings": "Settings"
"collections": {
"sections": "Sections",
"sections_description": "Allow access to the following sections",
"settings": "Settings",
"settings_description": "Define read and write access for settings areas"
}
},
"login": {
+7
View File
@@ -11,4 +11,11 @@ h2.ui-headline
{
font-size: var(--font-size-xl);
}
.-minor
{
font-size: var(--font-size);
color: var(--color-fg-mid);
font-weight: 400;
}
}
+38 -8
View File
@@ -94,19 +94,49 @@ namespace zero.Web
opts.Sections.Add<SettingsSection>();
SettingsGroup systemSettings = new SettingsGroup("@settings.groups.system");
systemSettings.Add(Constants.SettingsAreas.Updates, "@settings.system.updates.name", "@settings.system.updates.text", "fth-check-circle");
systemSettings.Add(Constants.SettingsAreas.Applications, "@settings.system.applications.name", "@settings.system.applications.text", "fth-layers");
systemSettings.Add(Constants.SettingsAreas.Users, "@settings.system.users.name", "@settings.system.users.text", "fth-users");
systemSettings.Add(Constants.SettingsAreas.Translations, "@settings.system.translations.name", "@settings.system.translations.text", "fth-type");
systemSettings.Add(Constants.SettingsAreas.Countries, "@settings.system.countries.name", "@settings.system.countries.text", "fth-map-pin");
systemSettings.Add(Constants.SettingsAreas.Logging, "@settings.system.logs.name", "@settings.system.logs.text", "fth-file-text");
systemSettings.Add(Constants.Settings.Updates, "@settings.system.updates.name", "@settings.system.updates.text", "fth-check-circle");
systemSettings.Add(Constants.Settings.Applications, "@settings.system.applications.name", "@settings.system.applications.text", "fth-layers");
systemSettings.Add(Constants.Settings.Users, "@settings.system.users.name", "@settings.system.users.text", "fth-users");
systemSettings.Add(Constants.Settings.Translations, "@settings.system.translations.name", "@settings.system.translations.text", "fth-type");
systemSettings.Add(Constants.Settings.Countries, "@settings.system.countries.name", "@settings.system.countries.text", "fth-map-pin");
systemSettings.Add(Constants.Settings.Logging, "@settings.system.logs.name", "@settings.system.logs.text", "fth-file-text");
SettingsGroup pluginSettings = new SettingsGroup("@settings.groups.plugins");
pluginSettings.Add("plugins", "@settings.plugins.installed.name", "@settings.plugins.installed.text", "fth-package");
pluginSettings.Add("createplugin", "@settings.plugins.create.name", "@settings.plugins.create.text", "fth-box");
pluginSettings.Add(Constants.Settings.Plugins, "@settings.plugins.installed.name", "@settings.plugins.installed.text", "fth-package");
pluginSettings.Add(Constants.Settings.CreatePlugin, "@settings.plugins.create.name", "@settings.plugins.create.text", "fth-box");
opts.SettingsAreas.Add(systemSettings);
opts.SettingsAreas.Add(pluginSettings);
PermissionCollection permissionSettings = new PermissionCollection()
{
Label = "@permission.collections.settings",
Description = "@permission.collections.settings_description"
};
permissionSettings.Items.Add(new Permission(Permissions.Settings.Updates, "@settings.system.updates.name", "@settings.system.updates.text_default", PermissionValueType.ReadWrite));
permissionSettings.Items.Add(new Permission(Permissions.Settings.Applications, "@settings.system.applications.name", "@settings.system.applications.text", PermissionValueType.ReadWrite));
permissionSettings.Items.Add(new Permission(Permissions.Settings.Users, "@settings.system.users.name", "@settings.system.users.text", PermissionValueType.ReadWrite));
permissionSettings.Items.Add(new Permission(Permissions.Settings.Translations, "@settings.system.translations.name", "@settings.system.translations.text", PermissionValueType.ReadWrite));
permissionSettings.Items.Add(new Permission(Permissions.Settings.Countries, "@settings.system.countries.name", "@settings.system.countries.text", PermissionValueType.ReadWrite));
permissionSettings.Items.Add(new Permission(Permissions.Settings.Logging, "@settings.system.logs.name", "@settings.system.logs.text", PermissionValueType.ReadWrite));
permissionSettings.Items.Add(new Permission(Permissions.Settings.Plugins, "@settings.plugins.installed.name", "@settings.plugins.installed.text_default", PermissionValueType.ReadWrite));
permissionSettings.Items.Add(new Permission(Permissions.Settings.CreatePlugin, "@settings.plugins.create.name", "@settings.plugins.create.text", PermissionValueType.ReadWrite));
PermissionCollection permissionSections = new PermissionCollection()
{
Label = "@permission.collections.sections",
Description = "@permission.collections.sections_description"
};
permissionSections.Items.Add(new Permission(Permissions.Sections.Dashboard, "@sections.item.dashboard", null, PermissionValueType.Boolean));
permissionSections.Items.Add(new Permission(Permissions.Sections.Pages, "@sections.item.pages", null, PermissionValueType.Boolean));
permissionSections.Items.Add(new Permission(Permissions.Sections.Lists, "@sections.item.lists", null, PermissionValueType.Boolean));
permissionSections.Items.Add(new Permission(Permissions.Sections.Media, "@sections.item.media", null, PermissionValueType.Boolean));
permissionSections.Items.Add(new Permission(Permissions.Sections.Settings, "@sections.item.settings", null, PermissionValueType.Boolean));
opts.Authorization.Permissions.Add(permissionSections);
opts.Authorization.Permissions.Add(permissionSettings);
}
+6 -6
View File
@@ -134,12 +134,12 @@ namespace zero.Web
sections.Add("settings", Constants.Sections.Settings);
Dictionary<string, string> settings = new Dictionary<string, string>();
settings.Add("applications", Constants.SettingsAreas.Applications);
settings.Add("countries", Constants.SettingsAreas.Countries);
settings.Add("logging", Constants.SettingsAreas.Logging);
settings.Add("translations", Constants.SettingsAreas.Translations);
settings.Add("updates", Constants.SettingsAreas.Updates);
settings.Add("users", Constants.SettingsAreas.Users);
settings.Add("applications", Constants.Settings.Applications);
settings.Add("countries", Constants.Settings.Countries);
settings.Add("logging", Constants.Settings.Logging);
settings.Add("translations", Constants.Settings.Translations);
settings.Add("updates", Constants.Settings.Updates);
settings.Add("users", Constants.Settings.Users);
aliases.Add("sections", sections);
aliases.Add("settings", settings);