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 13 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
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using OrchardCore.ContentTypes.Editors;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Infrastructure.Security;
using OrchardCore.Security.Services;

namespace OrchardCore.ContentFields.Settings;
Expand All @@ -24,8 +25,7 @@ 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)
var roles = (await _roleService.GetRoleNamesAsync(role => role.Type != RoleType.System))
.Select(roleName => new RoleEntry
{
Role = roleName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using OrchardCore.Environment.Extensions;
using OrchardCore.Environment.Extensions.Features;
using OrchardCore.Environment.Shell;
using OrchardCore.Infrastructure.Security;
using OrchardCore.Roles.Core;
using OrchardCore.Roles.ViewModels;
using OrchardCore.Security;
using OrchardCore.Security.Permissions;
Expand All @@ -28,6 +30,7 @@ public sealed class AdminController : Controller
private readonly IShellFeaturesManager _shellFeaturesManager;
private readonly IRoleService _roleService;
private readonly INotifier _notifier;
private readonly IRoleTracker _roleTracker;

internal readonly IStringLocalizer S;
internal readonly IHtmlLocalizer H;
Expand All @@ -41,6 +44,7 @@ public AdminController(
IShellFeaturesManager shellFeaturesManager,
IRoleService roleService,
INotifier notifier,
IRoleTracker roleTracker,
IStringLocalizer<AdminController> stringLocalizer,
IHtmlLocalizer<AdminController> htmlLocalizer)
{
Expand All @@ -52,6 +56,7 @@ public AdminController(
_shellFeaturesManager = shellFeaturesManager;
_roleService = roleService;
_notifier = notifier;
_roleTracker = roleTracker;
S = stringLocalizer;
H = htmlLocalizer;
}
Expand All @@ -67,7 +72,12 @@ public async Task<ActionResult> Index()

var model = new RolesViewModel
{
RoleEntries = roles.Select(BuildRoleEntry).ToList()
RoleEntries = roles.Select(role => new RoleEntry
{
Name = role.RoleName,
Description = role.RoleDescription,
Type = role.Type,
}).ToList()
};

return View(model);
Expand Down Expand Up @@ -110,11 +120,25 @@ public async Task<IActionResult> Create(CreateRoleViewModel model)

if (ModelState.IsValid)
{
var role = new Role { RoleName = model.RoleName, RoleDescription = model.RoleDescription };
var role = new Role
{
RoleName = model.RoleName,
RoleDescription = model.RoleDescription,
Type = RoleHelper.SystemRoleNames.Contains(model.RoleName)
? RoleType.System
: model.IsOwnerType ? RoleType.Owner : RoleType.Standard,
};

var result = await _roleManager.CreateAsync(role);

if (result.Succeeded)
{
if (role.Type == RoleType.Owner)
{
await _roleTracker.AddAsync(role);
}
await _notifier.SuccessAsync(H["Role created successfully."]);

return RedirectToAction(nameof(Index));
}

Expand All @@ -126,7 +150,7 @@ 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);
}

Expand All @@ -145,10 +169,22 @@ public async Task<IActionResult> Delete(string id)
return NotFound();
}

if (currentRole.Type == RoleType.System)
{
await _notifier.ErrorAsync(H["System roles cannot be deleted."]);

return RedirectToAction(nameof(Index));
}

var result = await _roleManager.DeleteAsync(currentRole);

if (result.Succeeded)
{
if (currentRole.Type == RoleType.Owner)
{
await _roleTracker.RemoveAsync(currentRole);
}

await _notifier.SuccessAsync(H["Role deleted successfully."]);
}
else
Expand Down Expand Up @@ -186,6 +222,7 @@ public async Task<IActionResult> Edit(string id)
Role = role,
Name = role.RoleName,
RoleDescription = role.RoleDescription,
IsOwnerType = role.Type == RoleType.Owner,
EffectivePermissions = await GetEffectivePermissions(role, allPermissions),
RoleCategoryPermissions = installedPermissions
};
Expand All @@ -194,7 +231,7 @@ public async Task<IActionResult> Edit(string id)
}

[HttpPost, ActionName(nameof(Edit))]
public async Task<IActionResult> EditPost(string id, string roleDescription)
public async Task<IActionResult> EditPost(string id, string roleDescription, bool hasFullAccess)
{
if (!await _authorizationService.AuthorizeAsync(User, CommonPermissions.ManageRoles))
{
Expand All @@ -206,39 +243,50 @@ public async Task<IActionResult> EditPost(string id, string roleDescription)
return NotFound();
}

if (hasFullAccess)
{
role.Type = RoleType.Owner;
}

role.RoleDescription = roleDescription;

// Save.
var rolePermissions = new List<RoleClaim>();
foreach (var key in Request.Form.Keys)
if (!hasFullAccess)
{
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(new RoleClaim
{
ClaimType = Permission.ClaimType,
ClaimValue = 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);

// After updating the document manager, update the role tracker.
if (role.Type == RoleType.Owner)
{
await _roleTracker.AddAsync(role);
}
else
{
await _roleTracker.RemoveAsync(role);
}

await _notifier.SuccessAsync(H["Role updated successfully."]);

return RedirectToAction(nameof(Index));
}

private RoleEntry BuildRoleEntry(IRole role)
{
return new RoleEntry
{
Name = role.RoleName,
Description = role.RoleDescription,
Selected = false
};
}

private async Task<IDictionary<PermissionGroupKey, IEnumerable<Permission>>> GetInstalledPermissionsAsync()
{
var installedPermissions = new Dictionary<PermissionGroupKey, IEnumerable<Permission>>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<!-- NuGet properties-->
<Title>OrchardCore Roles</Title>
<Description>$(OCCMSDescription)

The roles module adds the ability to manage roles and assign permissions to roles.</Description>
<Description>
$(OCCMSDescription)

The roles module adds the ability to manage roles and assign permissions to roles.
</Description>
<PackageTags>$(PackageTags) OrchardCoreCMS</PackageTags>
</PropertyGroup>

Expand Down
14 changes: 13 additions & 1 deletion src/OrchardCore.Modules/OrchardCore.Roles/Recipes/RolesStep.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System.Text.Json.Nodes;
using Microsoft.AspNetCore.Identity;
using OrchardCore.Infrastructure.Security;
using OrchardCore.Recipes.Models;
using OrchardCore.Recipes.Services;
using OrchardCore.Security;
using OrchardCore.Security.Permissions;
using OrchardCore.Security.Services;

namespace OrchardCore.Roles.Recipes;

Expand Down Expand Up @@ -42,11 +44,17 @@ public async Task ExecuteAsync(RecipeExecutionContext context)
{
role = new Role
{
RoleName = importedRole.Name
RoleName = importedRole.Name,
};
}

var isSystemRole = RoleHelper.SystemRoleNames.Contains(importedRole.Name);

role.RoleDescription = importedRole.Description;
role.Type = isSystemRole
? RoleType.System
: importedRole.HasFullAccess ? RoleType.Owner : RoleType.Standard;

role.RoleClaims.RemoveAll(c => c.ClaimType == Permission.ClaimType);
role.RoleClaims.AddRange(importedRole.Permissions.Select(p => new RoleClaim
{
Expand Down Expand Up @@ -74,6 +82,10 @@ public sealed class RolesStepModel
public sealed class RolesStepRoleModel
{
public string Name { get; set; }

public string Description { get; set; }

public bool HasFullAccess { get; set; }

public string[] Permissions { get; set; }
}
3 changes: 3 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.Roles/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using OrchardCore.Modules;
using OrchardCore.Navigation;
using OrchardCore.Recipes;
using OrchardCore.Roles.Core;
using OrchardCore.Roles.Deployment;
using OrchardCore.Roles.Recipes;
using OrchardCore.Roles.Services;
Expand All @@ -20,6 +21,8 @@ public sealed class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IAuthorizationHandler, RolesPermissionHandler>();
services.AddScoped<IRoleTracker, RoleTracker>();
services.AddScoped<RoleStore>();
services.Replace(ServiceDescriptor.Scoped<IRoleClaimStore<IRole>>(sp => sp.GetRequiredService<RoleStore>()));
services.Replace(ServiceDescriptor.Scoped<IRoleStore<IRole>>(sp => sp.GetRequiredService<RoleStore>()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ public class CreateRoleViewModel
public string RoleName { get; set; }

public string RoleDescription { get; set; }

public bool IsOwnerType { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ namespace OrchardCore.Roles.ViewModels;
public class EditRoleViewModel
{
public string Name { get; set; }

public string RoleDescription { get; set; }

public bool IsOwnerType { get; set; }

[BindNever]
public IDictionary<PermissionGroupKey, IEnumerable<Permission>> RoleCategoryPermissions { get; set; }

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using OrchardCore.Infrastructure.Security;

namespace OrchardCore.Roles.ViewModels;

public class RolesViewModel
Expand All @@ -8,6 +10,10 @@ public class RolesViewModel
public class RoleEntry
{
public string Name { get; set; }

public string Description { get; set; }

public bool Selected { get; set; }

public RoleType Type { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@
<div asp-validation-summary="ModelOnly"></div>
<form asp-action="Create" method="post" class="no-multisubmit">
<div class="mb-3" asp-validation-class-for="RoleName">
<label asp-for="RoleName" class="form-label">@T["Role name"]</label>
<label asp-for="RoleName" class="form-label">@T["Name"]</label>
<input asp-for="RoleName" class="form-control" autofocus />
<span asp-validation-for="RoleName" class="text-danger"></span>
</div>

<div class="mb-3" asp-validation-class-for="RoleDescription">
<label asp-for="RoleDescription" class="form-label">@T["Role description"]</label>
<input asp-for="RoleDescription" class="form-control" autofocus />
<label asp-for="RoleDescription" class="form-label">@T["Description"]</label>
<input asp-for="RoleDescription" class="form-control" />
<span asp-validation-for="RoleDescription" class="text-danger"></span>
</div>

<div class="mb-3">
<div class="form-check">
<input type="checkbox" class="form-check-input" asp-for="IsOwnerType" checked="@Model.IsOwnerType" role="button" />
<label class="form-check-label" asp-for="IsOwnerType">@T["Site Owner?"]</label>
<span class="hint dashed">@T["Roles with the Owner type will automatically grant the user full access to all permissions."]</span>
</div>
</div>

<div class="mb-3">
Expand Down
Loading