Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate SiteOwner permission and retain Administrator as system role #16781

Merged
merged 73 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
0274c67
Add RoleType and HasFullAccess to IRole
MikeAlhayek Sep 22, 2024
386f582
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 23, 2024
b02fa1a
update recipes
MikeAlhayek Sep 23, 2024
813f547
Merge branch 'ma/update-roles' of https://github.com/OrchardCMS/Orcha…
MikeAlhayek Sep 23, 2024
067ad37
fix memory key
MikeAlhayek Sep 23, 2024
cfc94a7
Don't assign role base claims when a role has full access
MikeAlhayek Sep 23, 2024
d897c89
cleanup
MikeAlhayek Sep 23, 2024
e6a9e00
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 23, 2024
ee4bf67
cleanup
MikeAlhayek Sep 23, 2024
56420bb
cleanup
MikeAlhayek Sep 23, 2024
9a473c1
Merge branch 'ma/update-roles' of https://github.com/OrchardCMS/Orcha…
MikeAlhayek Sep 23, 2024
4e4bbf2
cleanup
MikeAlhayek Sep 23, 2024
0d59175
Replace HasFullAccess property with Owner type
MikeAlhayek Sep 24, 2024
0b9e696
address feedback
MikeAlhayek Sep 24, 2024
446a62d
rename
MikeAlhayek Sep 24, 2024
8acc4c5
Update ViewMediaFolderAuthorizationHandlerTests.cs
MikeAlhayek Sep 24, 2024
d8d5829
Update OwnerRoleTrackerTest.cs
MikeAlhayek Sep 24, 2024
155e372
Update OwnerRoleTrackerTest.cs
MikeAlhayek Sep 24, 2024
3b77bdf
Update RolesPermissionHandlerTests.cs
MikeAlhayek Sep 24, 2024
eec8d9c
Update 2.1.0.md
MikeAlhayek Sep 24, 2024
282f142
Update 2.1.0.md
MikeAlhayek Sep 24, 2024
0bd8850
Update Edit.cshtml
MikeAlhayek Sep 24, 2024
3352174
address feedback and fix a bug with backward compatibility.
MikeAlhayek Sep 24, 2024
84ed649
deprecate SitePermission
MikeAlhayek Sep 24, 2024
fc1e46d
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 24, 2024
f79d924
fix file name
MikeAlhayek Sep 24, 2024
9d35419
Merge branch 'ma/update-roles' of https://github.com/OrchardCMS/Orcha…
MikeAlhayek Sep 24, 2024
0cd08cf
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 24, 2024
6c8fc45
remove the old test
MikeAlhayek Sep 24, 2024
4bf95b2
add comma
MikeAlhayek Sep 24, 2024
7699b41
Update src/OrchardCore.Modules/OrchardCore.ContentFields/Settings/Use…
MikeAlhayek Sep 24, 2024
024ea87
Update 2.1.0.md
MikeAlhayek Sep 24, 2024
5273938
Update 2.1.0.md
MikeAlhayek Sep 24, 2024
9f08c3a
merge conflict
MikeAlhayek Sep 24, 2024
0a86db0
fix UI bug
MikeAlhayek Sep 24, 2024
c905bd6
remove question marks
MikeAlhayek Sep 25, 2024
cad1515
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 25, 2024
d217b43
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 25, 2024
c398d46
remove the OwnerRoleCache
MikeAlhayek Sep 25, 2024
385c513
Merge branch 'ma/update-roles' of https://github.com/OrchardCMS/Orcha…
MikeAlhayek Sep 25, 2024
18a380b
Use flags for role type, cleanup the UI and code
MikeAlhayek Sep 25, 2024
cc9771d
don't normalize name before lookup since the manager does that already
MikeAlhayek Sep 25, 2024
3cd1872
cleanup
MikeAlhayek Sep 25, 2024
4e0332e
update release notes
MikeAlhayek Sep 25, 2024
dec0160
update recipes
MikeAlhayek Sep 25, 2024
720d210
use new RoleClaim constructors
MikeAlhayek Sep 25, 2024
8caef98
cleanup
MikeAlhayek Sep 25, 2024
9b2b5e2
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 25, 2024
71bf1bf
Update src/OrchardCore/OrchardCore.Recipes.Core/RecipePermissions.cs
MikeAlhayek Sep 26, 2024
d0c9ab6
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 26, 2024
151f2c2
Merge branch 'main' into ma/update-roles
MikeAlhayek Sep 26, 2024
a1a2e17
do not use RoleType, instead use Admin as a system role
MikeAlhayek Sep 26, 2024
788a81b
Cleanup by adding new methods to IRoleService
MikeAlhayek Sep 27, 2024
39d892f
cleanup
MikeAlhayek Sep 27, 2024
fa4745f
Fix role not found exception
MikeAlhayek Sep 28, 2024
0b3aeb5
cleanup
MikeAlhayek Oct 1, 2024
3430862
Update src/OrchardCore/OrchardCore.Infrastructure.Abstractions/Securi…
MikeAlhayek Oct 1, 2024
67aa6c1
address feedback
MikeAlhayek Oct 1, 2024
0144cbb
Merge branch 'ma/update-roles' of https://github.com/OrchardCMS/Orcha…
MikeAlhayek Oct 1, 2024
53ef5cc
Merge branch 'main' into ma/update-roles
MikeAlhayek Oct 1, 2024
d9bd7a3
cleanup
MikeAlhayek Oct 1, 2024
9479dac
Merge branch 'ma/update-roles' of https://github.com/OrchardCMS/Orcha…
MikeAlhayek Oct 1, 2024
8d13539
Adding role descriptions to recipes
Piedone Oct 2, 2024
231986f
Update RolesMigrations.cs
MikeAlhayek Oct 2, 2024
1c71b32
Update StandardPermissions.cs
MikeAlhayek Oct 2, 2024
d7c22ba
cleanup RoleClaim
MikeAlhayek Oct 2, 2024
e195717
Allow editing Administrator descriptions
MikeAlhayek Oct 2, 2024
0e3cd8a
reduce allocation
MikeAlhayek Oct 2, 2024
11a1c58
Fix RoleUpdater
MikeAlhayek Oct 2, 2024
2981731
address feedback
MikeAlhayek Oct 3, 2024
c511c2f
Merge branch 'main' into ma/update-roles
MikeAlhayek Oct 3, 2024
3b848eb
update docs
MikeAlhayek Oct 3, 2024
90e4ac6
Merge branch 'ma/update-roles' of https://github.com/OrchardCMS/Orcha…
MikeAlhayek Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading