Skip to content

Commit

Permalink
Deprecate SiteOwner permission and retain Administrator as system r…
Browse files Browse the repository at this point in the history
…ole (#16781)

Co-authored-by: Zoltán Lehóczky <[email protected]>
Co-authored-by: Sébastien Ros <[email protected]>
Co-authored-by: Georg von Kries <[email protected]>
  • Loading branch information
4 people authored Oct 3, 2024
1 parent cff607a commit c14840a
Show file tree
Hide file tree
Showing 64 changed files with 1,116 additions and 351 deletions.
6 changes: 5 additions & 1 deletion src/OrchardCore.Cms.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,11 @@
// "Key": ""
// }
//},
// "Url": "http://localhost",
// Roles
//"OrchardCore_Roles": {
// "AdminRoleName":"Administrator"
//},
//"Url": "http://localhost",
// "Ports": [ 9200 ],
// "Username": "admin",
// "Password": "admin",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ public override IDisplayResult Edit(ContentPartFieldDefinition partFieldDefiniti
model.Hint = settings.Hint;
model.Required = settings.Required;
model.Multiple = settings.Multiple;
var roles = (await _roleService.GetRoleNamesAsync())
.Except(RoleHelper.SystemRoleNames, StringComparer.OrdinalIgnoreCase)
.Select(roleName => new RoleEntry
{
Role = roleName,
IsSelected = settings.DisplayedRoles.Contains(roleName, StringComparer.OrdinalIgnoreCase)
})
.ToArray();
var roles = await _roleService.GetAssignableRolesAsync();
var roleEntries = roles.Select(role => new RoleEntry
{
Role = role.RoleName,
IsSelected = settings.DisplayedRoles.Contains(role.RoleName, StringComparer.OrdinalIgnoreCase),
}).ToArray();
model.Roles = roles;
model.DisplayAllUsers = settings.DisplayAllUsers || !roles.Where(x => x.IsSelected).Any();
model.Roles = roleEntries;
model.DisplayAllUsers = settings.DisplayAllUsers || !roleEntries.Where(x => x.IsSelected).Any();
}).Location("Content");
}

Expand All @@ -51,7 +49,12 @@ public override async Task<IDisplayResult> UpdateAsync(ContentPartFieldDefinitio
Multiple = model.Multiple
};

var selectedRoles = model.Roles.Where(x => x.IsSelected).Select(x => x.Role).ToArray();
var roles = await _roleService.GetAssignableRolesAsync();

var selectedRoles = model.Roles
.Where(x => x.IsSelected && roles.Any(y => y.RoleName == x.Role))
.Select(x => x.Role)
.ToArray();

if (model.DisplayAllUsers || selectedRoles.Length == 0)
{
Expand Down
3 changes: 1 addition & 2 deletions src/OrchardCore.Modules/OrchardCore.Recipes/AdminMenu.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Microsoft.Extensions.Localization;
using OrchardCore.Navigation;
using OrchardCore.Security;

namespace OrchardCore.Recipes;

Expand All @@ -20,7 +19,7 @@ protected override ValueTask BuildAsync(NavigationBuilder builder)
.Add(S["Recipes"], S["Recipes"].PrefixPosition(), recipes => recipes
.AddClass("recipes")
.Id("recipes")
.Permission(StandardPermissions.SiteOwner)
.Permission(RecipePermissions.ManageRecipes)
.Action("Index", "Admin", "OrchardCore.Recipes")
.LocalNav()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using OrchardCore.Recipes.Models;
using OrchardCore.Recipes.Services;
using OrchardCore.Recipes.ViewModels;
using OrchardCore.Security;

namespace OrchardCore.Recipes.Controllers;

Expand Down Expand Up @@ -60,7 +59,7 @@ public AdminController(
[Admin("Recipes", "Recipes")]
public async Task<ActionResult> Index()
{
if (!await _authorizationService.AuthorizeAsync(User, StandardPermissions.SiteOwner))
if (!await _authorizationService.AuthorizeAsync(User, RecipePermissions.ManageRecipes))
{
return Forbid();
}
Expand All @@ -86,7 +85,7 @@ public async Task<ActionResult> Index()
[HttpPost]
public async Task<ActionResult> Execute(string basePath, string fileName)
{
if (!await _authorizationService.AuthorizeAsync(User, StandardPermissions.SiteOwner))
if (!await _authorizationService.AuthorizeAsync(User, RecipePermissions.ManageRecipes))
{
return Forbid();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using OrchardCore.Security.Permissions;

namespace OrchardCore.Recipes;

public sealed class RecipesPermissionProvider : IPermissionProvider
{
private readonly IEnumerable<Permission> _allPermissions =
[
RecipePermissions.ManageRecipes,
];
public Task<IEnumerable<Permission>> GetPermissionsAsync()
=> Task.FromResult(_allPermissions);

public IEnumerable<PermissionStereotype> GetDefaultStereotypes() =>
[
new PermissionStereotype
{
Name = OrchardCoreConstants.Roles.Administrator,
Permissions = _allPermissions,
},
];
}
3 changes: 2 additions & 1 deletion src/OrchardCore.Modules/OrchardCore.Recipes/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using OrchardCore.Navigation;
using OrchardCore.Recipes.RecipeSteps;
using OrchardCore.Recipes.Services;
using OrchardCore.Security.Permissions;

namespace OrchardCore.Recipes;

Expand All @@ -15,7 +16,7 @@ public sealed class Startup : StartupBase
public override void ConfigureServices(IServiceCollection services)
{
services.AddNavigationProvider<AdminMenu>();

services.AddPermissionProvider<RecipesPermissionProvider>();
services.AddRecipeExecutionStep<CommandStep>();
services.AddRecipeExecutionStep<RecipesStep>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,21 @@ public async Task<ActionResult> Index()

var roles = await _roleService.GetRolesAsync();

var model = new RolesViewModel
var model = new RolesViewModel()
{
RoleEntries = roles.OrderBy(r => r.RoleName).Select(BuildRoleEntry).ToList()
RoleEntries = [],
};

foreach (var role in roles.OrderBy(r => r.RoleName))
{
model.RoleEntries.Add(new RoleEntry
{
Name = role.RoleName,
Description = role.RoleDescription,
IsSystemRole = await _roleService.IsSystemRoleAsync(role.RoleName),
});
}

return View(model);
}

Expand Down Expand Up @@ -102,19 +112,26 @@ public async Task<IActionResult> Create(CreateRoleViewModel model)
ModelState.AddModelError(string.Empty, S["Invalid role name."]);
}

if (await _roleManager.FindByNameAsync(_roleManager.NormalizeKey(model.RoleName)) != null)
if (await _roleManager.FindByNameAsync(model.RoleName) != null)
{
ModelState.AddModelError(string.Empty, S["The role is already used."]);
}
}

if (ModelState.IsValid)
{
var role = new Role { RoleName = model.RoleName, RoleDescription = model.RoleDescription };
var role = new Role
{
RoleName = model.RoleName,
RoleDescription = model.RoleDescription,
};

var result = await _roleManager.CreateAsync(role);

if (result.Succeeded)
{
await _notifier.SuccessAsync(H["Role created successfully."]);

return RedirectToAction(nameof(Index));
}

Expand All @@ -126,70 +143,39 @@ public async Task<IActionResult> Create(CreateRoleViewModel model)
}
}

// If we got this far, something failed, redisplay form
// If we got this far, something failed, redisplay form.
return View(model);
}

[HttpPost]
public async Task<IActionResult> Delete(string id)
{
if (!await _authorizationService.AuthorizeAsync(User, CommonPermissions.ManageRoles))
{
return Forbid();
}

var currentRole = await _roleManager.FindByIdAsync(id);

if (currentRole == null)
{
return NotFound();
}

var result = await _roleManager.DeleteAsync(currentRole);

if (result.Succeeded)
{
await _notifier.SuccessAsync(H["Role deleted successfully."]);
}
else
{
await _documentStore.CancelAsync();

await _notifier.ErrorAsync(H["Could not delete this role."]);

foreach (var error in result.Errors)
{
await _notifier.ErrorAsync(H[error.Description]);
}
}

return RedirectToAction(nameof(Index));
}

public async Task<IActionResult> Edit(string id)
{
if (!await _authorizationService.AuthorizeAsync(User, CommonPermissions.ManageRoles))
{
return Forbid();
}

if (await _roleManager.FindByNameAsync(_roleManager.NormalizeKey(id)) is not Role role)
if (await _roleManager.FindByIdAsync(id) is not Role role)
{
return NotFound();
}

var installedPermissions = await GetInstalledPermissionsAsync();
var allPermissions = installedPermissions.SelectMany(x => x.Value);

var model = new EditRoleViewModel
{
Role = role,
Name = role.RoleName,
RoleDescription = role.RoleDescription,
EffectivePermissions = await GetEffectivePermissions(role, allPermissions),
RoleCategoryPermissions = installedPermissions
IsAdminRole = await _roleService.IsAdminRoleAsync(role.RoleName),
};

if (!await _roleService.IsAdminRoleAsync(role.RoleName))
{
var installedPermissions = await GetInstalledPermissionsAsync();
var allPermissions = installedPermissions.SelectMany(x => x.Value);

model.EffectivePermissions = await GetEffectivePermissions(role, allPermissions);
model.RoleCategoryPermissions = installedPermissions;
}

return View(model);
}

Expand All @@ -201,26 +187,29 @@ public async Task<IActionResult> EditPost(string id, string roleDescription)
return Forbid();
}

if (await _roleManager.FindByNameAsync(_roleManager.NormalizeKey(id)) is not Role role)
if (await _roleManager.FindByIdAsync(id) is not Role role)
{
return NotFound();
}

role.RoleDescription = roleDescription;

// Save.
var rolePermissions = new List<RoleClaim>();
foreach (var key in Request.Form.Keys)
if (!await _roleService.IsAdminRoleAsync(role.RoleName))
{
if (key.StartsWith("Checkbox.", StringComparison.Ordinal) && Request.Form[key] == "true")
var rolePermissions = new List<RoleClaim>();

foreach (var key in Request.Form.Keys)
{
var permissionName = key["Checkbox.".Length..];
rolePermissions.Add(new RoleClaim { ClaimType = Permission.ClaimType, ClaimValue = permissionName });
if (key.StartsWith("Checkbox.", StringComparison.Ordinal) && Request.Form[key] == "true")
{
var permissionName = key["Checkbox.".Length..];
rolePermissions.Add(RoleClaim.Create(permissionName));
}
}
}

role.RoleClaims.RemoveAll(c => c.ClaimType == Permission.ClaimType);
role.RoleClaims.AddRange(rolePermissions);
role.RoleClaims.RemoveAll(c => c.ClaimType == Permission.ClaimType);
role.RoleClaims.AddRange(rolePermissions);
}

await _roleManager.UpdateAsync(role);

Expand All @@ -229,14 +218,47 @@ public async Task<IActionResult> EditPost(string id, string roleDescription)
return RedirectToAction(nameof(Index));
}

private RoleEntry BuildRoleEntry(IRole role)
[HttpPost]
public async Task<IActionResult> Delete(string id)
{
return new RoleEntry
if (!await _authorizationService.AuthorizeAsync(User, CommonPermissions.ManageRoles))
{
Name = role.RoleName,
Description = role.RoleDescription,
Selected = false
};
return Forbid();
}

var role = await _roleManager.FindByIdAsync(id);

if (role == null)
{
return NotFound();
}

if (await _roleService.IsSystemRoleAsync(role.RoleName))
{
await _notifier.ErrorAsync(H["System roles cannot be deleted."]);

return RedirectToAction(nameof(Index));
}

var result = await _roleManager.DeleteAsync(role);

if (result.Succeeded)
{
await _notifier.SuccessAsync(H["Role deleted successfully."]);
}
else
{
await _documentStore.CancelAsync();

await _notifier.ErrorAsync(H["Could not delete this role."]);

foreach (var error in result.Errors)
{
await _notifier.ErrorAsync(new LocalizedHtmlString(error.Description, error.Description));
}
}

return RedirectToAction(nameof(Index));
}

private async Task<IDictionary<PermissionGroupKey, IEnumerable<Permission>>> GetInstalledPermissionsAsync()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlan

foreach (var role in allRoles)
{
var currentRole = (Role)await _roleManager.FindByNameAsync(_roleManager.NormalizeKey(role.RoleName));
var currentRole = await _roleManager.FindByNameAsync(role.RoleName);

if (currentRole != null)
if (currentRole is Role r)
{
permissions.Add(JObject.FromObject(
new RolesStepRoleModel
{
Name = currentRole.RoleName,
Description = currentRole.RoleDescription,
Permissions = currentRole.RoleClaims.Where(x => x.ClaimType == Permission.ClaimType).Select(x => x.ClaimValue).ToArray()
Name = r.RoleName,
Description = r.RoleDescription,
Permissions = r.RoleClaims.Where(x => x.ClaimType == Permission.ClaimType).Select(x => x.ClaimValue).ToArray()
}));
}
}
Expand Down
Loading

0 comments on commit c14840a

Please sign in to comment.