diff --git a/src/Orchard.Web/Core/Settings/Permissions.cs b/src/Orchard.Web/Core/Settings/Permissions.cs index c361b4b0067..62eeca63d5e 100644 --- a/src/Orchard.Web/Core/Settings/Permissions.cs +++ b/src/Orchard.Web/Core/Settings/Permissions.cs @@ -6,7 +6,7 @@ namespace Orchard.Core.Settings { public class Permissions : IPermissionProvider { - public static readonly Permission ManageSettings = new Permission { Description = "Manage Settings", Name = "ManageSettings" }; + public static readonly Permission ManageSettings = new Permission { Description = "Manage Settings", Name = "ManageSettings", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } @@ -28,4 +28,4 @@ public IEnumerable GetDefaultStereotypes() } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Permissions.cs b/src/Orchard.Web/Modules/Orchard.AuditTrail/Permissions.cs index d42d5b0f413..9aecc64f4ea 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Permissions.cs @@ -6,10 +6,10 @@ namespace Orchard.AuditTrail { public class Permissions : IPermissionProvider { - public static readonly Permission ViewAuditTrail = new Permission { Description = "View audit trail", Name = "ViewAuditTrail" }; - public static readonly Permission ManageAuditTrailSettings = new Permission { Description = "Manage audit trail settings", Name = "ManageAuditTrailSettings" }; - public static readonly Permission ImportAuditTrail = new Permission { Description = "Import audit trail", Name = "ImportAuditTrail" }; - public static readonly Permission ManageClientIpAddressSettings = new Permission { Description = "Manage client IP address settings", Name = "ManageClientIpAddressSettings" }; + public static readonly Permission ViewAuditTrail = new Permission { Description = "View audit trail", Name = "ViewAuditTrail", IsSecurityCritical = true }; + public static readonly Permission ManageAuditTrailSettings = new Permission { Description = "Manage audit trail settings", Name = "ManageAuditTrailSettings", IsSecurityCritical = true }; + public static readonly Permission ImportAuditTrail = new Permission { Description = "Import audit trail", Name = "ImportAuditTrail", IsSecurityCritical = true }; + public static readonly Permission ManageClientIpAddressSettings = new Permission { Description = "Manage client IP address settings", Name = "ManageClientIpAddressSettings", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } @@ -35,4 +35,4 @@ public IEnumerable GetDefaultStereotypes() }; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs b/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs index e94bbbcd5a2..ab0935390ce 100644 --- a/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.ContentTypes/Permissions.cs @@ -7,7 +7,7 @@ namespace Orchard.ContentTypes public class Permissions : IPermissionProvider { public static readonly Permission ViewContentTypes = new Permission { Name = "ViewContentTypes", Description = "View content types" }; - public static readonly Permission EditContentTypes = new Permission { Name = "EditContentTypes", Description = "Edit content types" }; + public static readonly Permission EditContentTypes = new Permission { Name = "EditContentTypes", Description = "Edit content types", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.ImportExport/Permissions.cs b/src/Orchard.Web/Modules/Orchard.ImportExport/Permissions.cs index 3d22ed26880..1d0d4140ef3 100644 --- a/src/Orchard.Web/Modules/Orchard.ImportExport/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.ImportExport/Permissions.cs @@ -6,8 +6,8 @@ namespace Orchard.ImportExport { public class Permissions : IPermissionProvider { - public static readonly Permission Import = new Permission { Description = "Import Data", Name = "Import" }; - public static readonly Permission Export = new Permission { Description = "Export Data", Name = "Export" }; + public static readonly Permission Import = new Permission { Description = "Import Data", Name = "Import", IsSecurityCritical = true }; + public static readonly Permission Export = new Permission { Description = "Export Data", Name = "Export", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } @@ -26,4 +26,4 @@ public IEnumerable GetDefaultStereotypes() }; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Modules/Permissions.cs b/src/Orchard.Web/Modules/Orchard.Modules/Permissions.cs index accbf1018b2..5aacb792bc9 100644 --- a/src/Orchard.Web/Modules/Orchard.Modules/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.Modules/Permissions.cs @@ -6,7 +6,7 @@ namespace Orchard.Modules { public class Permissions : IPermissionProvider { - public static readonly Permission ManageFeatures = new Permission { Description = "Manage Features", Name = "ManageFeatures" }; + public static readonly Permission ManageFeatures = new Permission { Description = "Manage Features", Name = "ManageFeatures", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } @@ -25,4 +25,4 @@ public IEnumerable GetDefaultStereotypes() }; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Packaging/Permissions.cs b/src/Orchard.Web/Modules/Orchard.Packaging/Permissions.cs index e85cbc31a52..3411d3f1535 100644 --- a/src/Orchard.Web/Modules/Orchard.Packaging/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.Packaging/Permissions.cs @@ -6,7 +6,7 @@ namespace Orchard.Packaging { public class Permissions : IPermissionProvider { - public static readonly Permission ManagePackages = new Permission { Description = "Manage packages", Name = "ManagePackages" }; + public static readonly Permission ManagePackages = new Permission { Description = "Manage packages", Name = "ManagePackages", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } @@ -21,4 +21,4 @@ public IEnumerable GetDefaultStereotypes() return new List(); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Roles/Controllers/AdminController.cs index 057e239dc2a..d1c27d3cc78 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Controllers/AdminController.cs @@ -65,7 +65,16 @@ public ActionResult Index() if (!Services.Authorizer.Authorize(Permissions.ManageRoles, T("Not authorized to manage roles"))) return new HttpUnauthorizedResult(); - var model = new RolesIndexViewModel { Rows = _roleService.GetRoles().OrderBy(r => r.Name).ToList() }; + var securityCriticalPermissions = _roleService.GetSecurityCriticalPermissions().ToHashSet(); + var roles = _roleService.GetRoles().OrderBy(r => r.Name).ToList(); + + var model = new RolesIndexViewModel + { + Rows = roles, + RolesWithSecurityCriticalPermissions = roles.ToDictionary( + role => role.Name, + role => role.RolesPermissions.Any(p => securityCriticalPermissions.Contains(p.Permission.Name))) + }; return View(model); } @@ -250,18 +259,21 @@ public ActionResult Assign(int id) { return new HttpUnauthorizedResult(); } + + var securityCriticalPermissions = _roleService.GetSecurityCriticalPermissions().ToHashSet(); // create the ViewModel used to manage a user's roles var model = new UserRolesViewModel { User = userRolesPart.As(), UserRoles = userRolesPart, - Roles = allRoles.Select(x => new UserRoleEntry + Roles = allRoles.Select(role => new UserRoleEntry { - RoleId = x.Id, - Name = x.Name, - Granted = userRolesPart.Roles.Contains(x.Name) + RoleId = role.Id, + Name = role.Name, + Granted = userRolesPart.Roles.Contains(role.Name), + HasSecurityCriticalPermissions = role.RolesPermissions.Any(p => securityCriticalPermissions.Contains(p.Permission.Name)) }).ToList(), - AuthorizedRoleIds = authorizedRoleIds + AuthorizedRoleIds = authorizedRoleIds, }; // this calls the same view used by the driver that lets users with higher diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Drivers/UserRolesPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Roles/Drivers/UserRolesPartDriver.cs index b3064ce3e2d..d268b0bf17c 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Drivers/UserRolesPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Drivers/UserRolesPartDriver.cs @@ -67,20 +67,22 @@ protected override DriverResult Editor(UserRolesPart userRolesPart, dynamic shap { return null; } - var allRoles = _allRoles.Value - .Select(x => new UserRoleEntry - { - RoleId = x.Id, - Name = x.Name, - Granted = userRolesPart.Roles.Contains(x.Name) - }); + + var securityCriticalPermissions = _roleService.GetSecurityCriticalPermissions().ToHashSet(); var model = new UserRolesViewModel { User = userRolesPart.As(), UserRoles = userRolesPart, - Roles = allRoles.ToList(), - AuthorizedRoleIds = authorizedRoleIds + Roles = _allRoles.Value.Select(role => new UserRoleEntry + { + RoleId = role.Id, + Name = role.Name, + Granted = userRolesPart.Roles.Contains(role.Name), + HasSecurityCriticalPermissions = role.RolesPermissions.Any(p => securityCriticalPermissions.Contains(p.Permission.Name)) + }).ToList(), + AuthorizedRoleIds = authorizedRoleIds, }; + return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix); }); diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Permissions.cs b/src/Orchard.Web/Modules/Orchard.Roles/Permissions.cs index 661cb80e16e..9aa8263040f 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Permissions.cs @@ -12,8 +12,8 @@ public class Permissions : IPermissionProvider { private readonly IRepository _roleRepository; - public static readonly Permission ManageRoles = new Permission { Description = "Managing Roles", Name = "ManageRoles" }; - public static readonly Permission AssignRoles = new Permission { Description = "Assign Roles", Name = "AssignRoles", ImpliedBy = new[] { ManageRoles } }; + public static readonly Permission ManageRoles = new Permission { Description = "Managing Roles", Name = "ManageRoles", IsSecurityCritical = true, }; + public static readonly Permission AssignRoles = new Permission { Description = "Assign Roles", Name = "AssignRoles", IsSecurityCritical = true, ImpliedBy = new[] { ManageRoles } }; public virtual Feature Feature { get; set; } @@ -80,4 +80,4 @@ public IEnumerable GetDefaultStereotypes() } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs b/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs index d4aaee97184..25787886b4b 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Services/IRoleService.cs @@ -14,6 +14,7 @@ public interface IRoleService : IDependency void UpdateRole(int id, string roleName, IEnumerable rolePermissions); void DeleteRole(int id); IDictionary> GetInstalledPermissions(); + IEnumerable GetSecurityCriticalPermissions(); IEnumerable GetPermissionsForRole(int id); IEnumerable GetPermissionsForRoleByName(string name); @@ -26,4 +27,4 @@ public interface IRoleService : IDependency /// Returns false if a role with the given name already exits bool VerifyRoleUnicity(string name); } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs b/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs index 14d36c5c591..46f22254971 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/Services/RoleService.cs @@ -203,6 +203,9 @@ public IDictionary> GetInstalledPermissions() return installedPermissions; } + public IEnumerable GetSecurityCriticalPermissions() => + _permissionProviders.SelectMany(pp => pp.GetPermissions().Where(p => p.IsSecurityCritical)).Select(p => p.Name); + public IEnumerable GetPermissionsForRole(int id) { var permissions = new List(); @@ -251,4 +254,4 @@ private void TriggerSignal() _signals.Trigger(SignalName); } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/RolesIndexViewModel.cs b/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/RolesIndexViewModel.cs index 5eaf316d37e..f2e52dd6b37 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/RolesIndexViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/RolesIndexViewModel.cs @@ -6,5 +6,7 @@ namespace Orchard.Roles.ViewModels public class RolesIndexViewModel { public IList Rows { get; set; } + + public Dictionary RolesWithSecurityCriticalPermissions { get; set; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/UserRolesViewModel.cs b/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/UserRolesViewModel.cs index 51171ee8854..8675deeedfe 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/UserRolesViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Roles/ViewModels/UserRolesViewModel.cs @@ -23,5 +23,6 @@ public class UserRoleEntry public int RoleId { get; set; } public string Name { get; set; } public bool Granted { get; set; } + public bool HasSecurityCriticalPermissions { get; set; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Edit.cshtml b/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Edit.cshtml index 3604401eb01..5a5b76e5989 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Edit.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Edit.cshtml @@ -1,67 +1,93 @@ +@using Orchard.Roles.ViewModels + @model RoleEditViewModel -@using Orchard.Roles.ViewModels; -@{ Layout.Title = T("Edit Role").ToString(); } +@{ + Style.Require("FontAwesome"); + Layout.Title = T("Edit Role").ToString(); +} -@using(Html.BeginFormAntiForgeryPost()) { +@using (Html.BeginFormAntiForgeryPost()) +{ @Html.ValidationSummary();
@T("Information") - @if (Model.Name == "Administrator") { // the one special case + @if (Model.Name == "Administrator") + { // the one special case } - else { + else + { }
@T("Permissions") - @foreach (var category in Model.RoleCategoryPermissions.Keys) { -
- @category - - - - - - - - - - - - - @foreach (var permission in Model.RoleCategoryPermissions[category]) { - - - - - - } -
@T("Permission")@T("Allow")@T("Effective")
@T(permission.Description) - @if (Model.CurrentPermissions.Contains(permission.Name)) { - - } - else { - - } - - @if (Model.EffectivePermissions.Contains(permission.Name)) { - - } else { - - } -
+ +

@T("Allow: Permission is granted explicitly.")

+

@T("Effective: Permission is implied by a higher level permission, or explicitly granted.")

+ +
+ + @foreach (var category in Model.RoleCategoryPermissions.Keys) + { +
+ @category + + + + + + + + + + + + + @foreach (var permission in Model.RoleCategoryPermissions[category]) + { + + + + + + } +
@T("Permission")@T("Allow")@T("Effective")
@T(permission.Description) + @if (Model.CurrentPermissions.Contains(permission.Name)) + { + + } + else + { + + } + @if (permission.IsSecurityCritical) + { + + } + + @if (Model.EffectivePermissions.Contains(permission.Name)) + { + + } + else + { + + } +
- } + }
- @if (Model.Name != "Administrator") { - + @if (Model.Name != "Administrator") + { + }
-} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Index.cshtml index f316f45d376..299e5e19d1d 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Roles/Views/Admin/Index.cshtml @@ -1,14 +1,17 @@ +@using Orchard.Roles.ViewModels + @model RolesIndexViewModel -@using Orchard.Roles.ViewModels; -@using Orchard.Utility.Extensions; + @{ Script.Require("ShapesBase"); + Style.Require("FontAwesome"); Layout.Title = T("Roles").ToString(); } -@using (Html.BeginFormAntiForgeryPost()) { - @Html.ValidationSummary(); +@using (Html.BeginFormAntiForgeryPost()) +{ + @Html.ValidationSummary()
- @Html.ActionLink(row.Name, "Edit", new { row.Id }) + + @Html.ActionLink(row.Name, "Edit", new { row.Id }) + @if (Model.RolesWithSecurityCriticalPermissions[row.Name]) + { + + } + diff --git a/src/Orchard.Web/Modules/Orchard.Roles/Views/EditorTemplates/Parts/Roles.UserRoles.cshtml b/src/Orchard.Web/Modules/Orchard.Roles/Views/EditorTemplates/Parts/Roles.UserRoles.cshtml index 245bbdd5b23..6eebac14c82 100644 --- a/src/Orchard.Web/Modules/Orchard.Roles/Views/EditorTemplates/Parts/Roles.UserRoles.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Roles/Views/EditorTemplates/Parts/Roles.UserRoles.cshtml @@ -4,13 +4,20 @@ @model UserRolesViewModel +@{ + Style.Require("FontAwesome"); +} +
@T("Roles") - @if (Model.Roles.Count > 0) { + @if (Model.Roles.Count > 0) + { var index = 0; - foreach (var entry in Model.Roles) { - if (SystemRoles.GetSystemRoles().Contains(entry.Name)) { + foreach (var entry in Model.Roles) + { + if (SystemRoles.GetSystemRoles().Contains(entry.Name)) + { continue; } @@ -18,17 +25,26 @@ @Html.Hidden("Roles[" + index + "].Name", entry.Name)
- @if (Model.AuthorizedRoleIds.Contains(entry.RoleId)) { + @if (Model.AuthorizedRoleIds.Contains(entry.RoleId)) + { @Html.CheckBox("Roles[" + index + "].Granted", entry.Granted) - } else { + } + else + { @Html.CheckBox("Roles[" + index + "].Granted", entry.Granted, new { disabled = true }) } + @if (entry.HasSecurityCriticalPermissions) + { + + }
index++; } - } else { + } + else + {

@T("There are no roles.")

}
diff --git a/src/Orchard.Web/Modules/Orchard.Templates/Permissions.cs b/src/Orchard.Web/Modules/Orchard.Templates/Permissions.cs index 339c947cfb1..8e5798e567f 100644 --- a/src/Orchard.Web/Modules/Orchard.Templates/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.Templates/Permissions.cs @@ -6,7 +6,7 @@ namespace Orchard.Templates { public class Permissions : IPermissionProvider { - public static readonly Permission ManageTemplates = new Permission { Description = "Managing Templates", Name = "ManageTemplates" }; + public static readonly Permission ManageTemplates = new Permission { Description = "Managing Templates", Name = "ManageTemplates", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } @@ -39,4 +39,4 @@ public IEnumerable GetDefaultStereotypes() }; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Themes/Permissions.cs b/src/Orchard.Web/Modules/Orchard.Themes/Permissions.cs index c3b9453a337..9e7746cca03 100644 --- a/src/Orchard.Web/Modules/Orchard.Themes/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.Themes/Permissions.cs @@ -6,7 +6,7 @@ namespace Orchard.Themes { public class Permissions : IPermissionProvider { - public static readonly Permission ApplyTheme = new Permission { Description = "Apply a Theme", Name = "ApplyTheme" }; + public static readonly Permission ApplyTheme = new Permission { Description = "Apply a Theme", Name = "ApplyTheme", IsSecurityCritical = true }; public virtual Feature Feature { get; set; } @@ -27,4 +27,4 @@ public IEnumerable GetDefaultStereotypes() }; } } -} \ No newline at end of file +} diff --git a/src/Orchard.Web/Modules/Orchard.Users/Permissions.cs b/src/Orchard.Web/Modules/Orchard.Users/Permissions.cs index 4fe1b0af422..4dff61218a5 100644 --- a/src/Orchard.Web/Modules/Orchard.Users/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.Users/Permissions.cs @@ -7,7 +7,7 @@ namespace Orchard.Users public class Permissions : IPermissionProvider { public static readonly Permission ManageUsers = - new Permission { Description = "Managing Users", Name = "ManageUsers" }; + new Permission { Description = "Managing Users", Name = "ManageUsers", IsSecurityCritical = true }; public static readonly Permission ViewUsers = new Permission { Description = "View List of Users", Name = "ViewUsers", ImpliedBy = new[] { ManageUsers } }; @@ -31,4 +31,4 @@ public IEnumerable GetDefaultStereotypes() } } -} \ No newline at end of file +} diff --git a/src/Orchard/Security/Permissions/Permission.cs b/src/Orchard/Security/Permissions/Permission.cs index 3fd2fab016b..c4ba72066b5 100644 --- a/src/Orchard/Security/Permissions/Permission.cs +++ b/src/Orchard/Security/Permissions/Permission.cs @@ -11,6 +11,11 @@ public class Permission public IEnumerable ImpliedBy { get; set; } + /// + /// Indicates whether this permission could allow a user to elevate their other permissions. + /// + public bool IsSecurityCritical { get; set; } + public static Permission Named(string name) { return new Permission { Name = name }; @@ -19,4 +24,4 @@ public static Permission Named(string name) [Obsolete("This property is not used anywhere, so it shouldn't be referenced.")] public bool RequiresOwnership { get; set; } } -} \ No newline at end of file +} diff --git a/src/Orchard/Security/StandardPermissions.cs b/src/Orchard/Security/StandardPermissions.cs index 812bed2c25e..4a04762ccba 100644 --- a/src/Orchard/Security/StandardPermissions.cs +++ b/src/Orchard/Security/StandardPermissions.cs @@ -10,7 +10,7 @@ public class StandardPermissions : IPermissionProvider { public static readonly Permission AccessAdminPanel = new Permission { Name = "AccessAdminPanel", Description = "Access admin panel" }; public static readonly Permission AccessFrontEnd = new Permission { Name = "AccessFrontEnd", Description = "Access site front-end" }; - public static readonly Permission SiteOwner = new Permission { Name = "SiteOwner", Description = "Site Owners Permission" }; + public static readonly Permission SiteOwner = new Permission { Name = "SiteOwner", Description = "Site Owners Permission", IsSecurityCritical = true }; public Feature Feature { @@ -79,4 +79,4 @@ public IEnumerable GetDefaultStereotypes() } } -} \ No newline at end of file +}