Roles: Fixing and DRYing IsInRoleActivity and RoleCondition to be able handle "Anonymous" and "Authenticated" + code styling, fixes

This commit is contained in:
Lombiq 2019-08-23 19:04:09 +02:00 committed by Benedek Farkas
parent bbd0d9bb16
commit 83ba470cd2
8 changed files with 121 additions and 81 deletions
src/Orchard.Web/Modules/Orchard.Roles

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Orchard.Environment.Extensions;
using Orchard.Localization;
using Orchard.Security;
using Orchard.Roles.Models;
using Orchard.Workflows.Models;
using Orchard.Workflows.Services;
@ -28,7 +28,7 @@ namespace Orchard.Roles.Activities {
}
public override LocalizedString Description {
get { return T("Whether the current user is in a specific role."); }
get { return T("Whether the current user is in a specific role."); }
}
public override string Form {
@ -36,7 +36,7 @@ namespace Orchard.Roles.Activities {
}
public override IEnumerable<LocalizedString> GetPossibleOutcomes(WorkflowContext workflowContext, ActivityContext activityContext) {
return new[] {T("Yes"), T("No")};
return new[] { T("Yes"), T("No") };
}
public override bool CanExecute(WorkflowContext workflowContext, ActivityContext activityContext) {
@ -44,51 +44,16 @@ namespace Orchard.Roles.Activities {
}
public override IEnumerable<LocalizedString> Execute(WorkflowContext workflowContext, ActivityContext activityContext) {
if (UserIsInRole(activityContext)) {
yield return T("Yes");
}
else {
yield return T("No");
}
yield return _workContextAccessor.GetContext().CurrentUser.UserIsInRole(GetRoles(activityContext)) ? T("Yes") : T("No");
}
private bool UserIsInRole(ActivityContext context) {
// checking if user is in an accepted role
var workContext = _workContextAccessor.GetContext();
var user = workContext.CurrentUser;
var roles = GetRoles(context);
return UserIsInRole(user, roles);
}
public static bool UserIsInRole(IUser user, IEnumerable<string> roles) {
bool isInRole = false;
if (user == null) {
isInRole = roles.Contains("Anonymous");
}
else {
dynamic dynUser = user.ContentItem;
if (dynUser.UserRolesPart != null) {
IEnumerable<string> userRoles = dynUser.UserRolesPart.Roles;
isInRole = userRoles.Any(roles.Contains);
}
}
return isInRole;
}
private IEnumerable<string> GetRoles(ActivityContext context) {
string roles = context.GetState<string>("Roles");
if (String.IsNullOrEmpty(roles)) {
return Enumerable.Empty<string>();
}
return roles.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList();
return string.IsNullOrEmpty(roles) ?
Enumerable.Empty<string>() :
roles.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList();
}
}
}

View File

@ -1,9 +1,8 @@
using Orchard.ContentManagement;
using System;
using System.Linq;
using Orchard.Events;
using Orchard.Roles.Models;
using Orchard.Security;
using System;
using System.Linq;
namespace Orchard.Roles.Conditions {
public interface IConditionProvider : IEventHandler {
@ -18,19 +17,14 @@ namespace Orchard.Roles.Conditions {
}
public void Evaluate(dynamic evaluationContext) {
if (!String.Equals(evaluationContext.FunctionName, "role", StringComparison.OrdinalIgnoreCase)) {
if (!string.Equals(evaluationContext.FunctionName, "role", StringComparison.OrdinalIgnoreCase)) {
return;
}
var user = _authenticationService.GetAuthenticatedUser();
if (user == null) {
evaluationContext.Result = false;
return;
}
var roles = ((object[])evaluationContext.Arguments).Cast<string>();
var userRoles = user.As<IUserRoles>();
evaluationContext.Result = userRoles != null && userRoles.Roles.Intersect(roles).Any();
evaluationContext.Result = user.UserIsInRole(roles);
}
}
}

View File

@ -0,0 +1,12 @@
using System.Collections.Generic;
namespace Orchard.Roles.Constants {
public static class SystemRoles {
public const string Anonymous = nameof(Anonymous);
public const string Authenticated = nameof(Authenticated);
public static IEnumerable<string> GetSystemRoles() {
return new List<string> { Anonymous, Authenticated };
}
}
}

View File

@ -0,0 +1,61 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.Roles.Constants;
using Orchard.Security;
namespace Orchard.Roles.Models {
public static class UserRolesExtensions {
/// <summary>
/// Determines whether the given User has any of the provided list of Roles.
/// </summary>
/// <param name="user">The User to examine.</param>
/// <param name="roles">The list of Roles to compare to User's Roles with.</param>
/// <returns>True if the User has any of the provided Roles.</returns>
public static bool UserIsInRole(this IUser user, IEnumerable<string> roles) {
return UserIsInRole(user.As<UserRolesPart>(), roles);
}
/// <summary>
/// Determines whether the given User has any of the provided list of Roles.
/// </summary>
/// <param name="user">The User to examine.</param>
/// <param name="roles">The list of Roles to compare to User's Roles with.</param>
/// <returns>True if the User has any of the provided Roles.</returns>
public static bool UserIsInRole(this UserRolesPart userRolesPart, IEnumerable<string> roles) {
if (!roles?.Any() ?? false) return false;
return userRolesPart == null ?
roles.Contains(SystemRoles.Anonymous) :
roles.Contains(SystemRoles.Authenticated) || userRolesPart.Roles.Any(roles.Contains);
}
/// <summary>
/// Returns the list of Roles the User has, including the ones
/// that are not assignable (Anonymous or Authenticated).
/// </summary>
/// <param name="user">The User whose Roles are to be retrieved.</param>
/// <returns>The User's list of Roles.</returns>
public static IEnumerable<string> GetRuntimeUserRoles(this IUser user) {
return GetRuntimeUserRoles(user.As<UserRolesPart>());
}
/// <summary>
/// Returns the list of Roles the User has, including the ones
/// that are not assignable (Anonymous or Authenticated).
/// </summary>
/// <param name="user">The UserRolesPart of the User whose Roles are to be retrieved.</param>
/// <returns>The User's list of Roles.</returns>
public static IEnumerable<string> GetRuntimeUserRoles(this UserRolesPart userRolesPart) {
var roles = new List<string>();
if (userRolesPart == null) roles.Add(SystemRoles.Anonymous);
else {
roles.Add(SystemRoles.Authenticated);
roles.AddRange(userRolesPart.Roles);
}
return roles;
}
}
}

View File

@ -7,6 +7,8 @@ using Orchard.Data.Migration;
using Orchard.Roles.Models;
using Orchard.Roles.Services;
using Orchard.Security;
using Orchard.Roles.Constants;
using ContentsPermissions = Orchard.Core.Contents.Permissions;
namespace Orchard.Roles {
public class RolesDataMigration : DataMigrationImpl {
@ -58,32 +60,32 @@ namespace Orchard.Roles {
public int UpdateFrom1() {
// creates default permissions for Orchard v1.4 instances and earlier
_roleService.CreatePermissionForRole("Anonymous", Orchard.Core.Contents.Permissions.ViewContent.Name);
_roleService.CreatePermissionForRole("Authenticated", Orchard.Core.Contents.Permissions.ViewContent.Name);
_roleService.CreatePermissionForRole(SystemRoles.Anonymous, ContentsPermissions.ViewContent.Name);
_roleService.CreatePermissionForRole(SystemRoles.Authenticated, ContentsPermissions.ViewContent.Name);
return 2;
}
public int UpdateFrom2() {
//Assigns the "Create Permission" to all roles able to create contents
var contentEditPermissions = new[] {
Core.Contents.Permissions.EditContent,
Core.Contents.Permissions.EditOwnContent
ContentsPermissions.EditContent,
ContentsPermissions.EditOwnContent
};
var dynamicPermissions = new Orchard.Core.Contents.DynamicPermissions(_contentDefinitionManager);
var dynamicPermissions = new DynamicPermissions(_contentDefinitionManager);
var securableTypes = _contentDefinitionManager.ListTypeDefinitions()
.Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Securable);
var permissionTemplates = Core.Contents.DynamicPermissions.PermissionTemplates;
var permissionTemplates = DynamicPermissions.PermissionTemplates;
List<object> dynContentPermissions = new List<object>();
foreach (var typeDefinition in securableTypes) {
dynContentPermissions.Add(new {
Permission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.EditContent.Name], typeDefinition),
CreatePermission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.CreateContent.Name], typeDefinition)
Permission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[ContentsPermissions.EditContent.Name], typeDefinition),
CreatePermission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[ContentsPermissions.CreateContent.Name], typeDefinition)
});
dynContentPermissions.Add(new {
Permission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.EditOwnContent.Name], typeDefinition),
CreatePermission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.CreateContent.Name], typeDefinition)
Permission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[ContentsPermissions.EditOwnContent.Name], typeDefinition),
CreatePermission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[ContentsPermissions.CreateContent.Name], typeDefinition)
});
}
var roles = _roleService.GetRoles();
@ -91,13 +93,13 @@ namespace Orchard.Roles {
var existingPermissionsNames = role.RolesPermissions.Select(x => x.Permission.Name).ToList();
var checkForDynamicPermissions = true;
var updateRole = false;
if (existingPermissionsNames.Any(x => x == Core.Contents.Permissions.CreateContent.Name)) {
if (existingPermissionsNames.Any(x => x == ContentsPermissions.CreateContent.Name)) {
continue; // Skipping this role cause it already has the Create content permission
}
var simulation = UserSimulation.Create(role.Name);
foreach (var contentEditPermission in contentEditPermissions) {
if (_authorizationService.TryCheckAccess(contentEditPermission, simulation, null)) {
existingPermissionsNames.Add(Core.Contents.Permissions.CreateContent.Name);
existingPermissionsNames.Add(ContentsPermissions.CreateContent.Name);
checkForDynamicPermissions = false;
updateRole = true;
break;

View File

@ -102,6 +102,7 @@
<Compile Include="Activities\UserTaskActivity.cs" />
<Compile Include="AdminMenu.cs" />
<Compile Include="Commands\RoleCommands.cs" />
<Compile Include="Constants\SystemRoles.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Drivers\UserTaskDriver.cs" />
<Compile Include="Events\IRoleEventHandler.cs" />
@ -115,6 +116,7 @@
<Compile Include="Events\UserAddedContext.cs" />
<Compile Include="Events\UserRemovedContext.cs" />
<Compile Include="Events\UserRoleContext.cs" />
<Compile Include="Extensions\UserRolesExtensions.cs" />
<Compile Include="Forms\SelectRolesForms.cs" />
<Compile Include="Forms\UserTaskForms.cs" />
<Compile Include="Recipes\Builders\RolesStep.cs" />

View File

@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.ContentManagement;
using Orchard.Roles.Constants;
using Orchard.Roles.Models;
using Orchard.Security;
using Orchard.Security.Permissions;
@ -13,8 +14,6 @@ namespace Orchard.Roles.Services {
private readonly IRoleService _roleService;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly IAuthorizationServiceEventHandler _authorizationServiceEventHandler;
private static readonly string[] AnonymousRole = new[] { "Anonymous" };
private static readonly string[] AuthenticatedRole = new[] { "Authenticated" };
public RolesBasedAuthorizationService(IRoleService roleService, IWorkContextAccessor workContextAccessor, IAuthorizationServiceEventHandler authorizationServiceEventHandler) {
_roleService = roleService;
@ -57,22 +56,22 @@ namespace Orchard.Roles.Services {
var grantingNames = PermissionNames(context.Permission, Enumerable.Empty<string>()).Distinct().ToArray();
// determine what set of roles should be examined by the access check
IEnumerable<string> rolesToExamine;
var rolesToExamine = new List<string>();
if (context.User == null) {
rolesToExamine = AnonymousRole;
rolesToExamine.Add(SystemRoles.Anonymous);
}
else if (context.User.Has<IUserRoles>()) {
// the current user is not null, so get his roles and add "Authenticated" to it
rolesToExamine = context.User.As<IUserRoles>().Roles;
rolesToExamine = context.User.As<IUserRoles>().Roles.ToList();
// when it is a simulated anonymous user in the admin
if (!rolesToExamine.Contains(AnonymousRole[0])) {
rolesToExamine = rolesToExamine.Concat(AuthenticatedRole);
if (!rolesToExamine.Contains(SystemRoles.Anonymous)) {
rolesToExamine.Add(SystemRoles.Authenticated);
}
}
else {
// the user is not null and has no specific role, then it's just "Authenticated"
rolesToExamine = AuthenticatedRole;
rolesToExamine.Add(SystemRoles.Authenticated);
}
foreach (var role in rolesToExamine) {

View File

@ -1,26 +1,31 @@
@using Orchard.Roles.Constants
@using Orchard.Roles.ViewModels
@using System.Linq
@model UserRolesViewModel
@using Orchard.Roles.ViewModels;
<fieldset>
<legend>@T("Roles")</legend>
@if (Model.Roles.Count > 0) {
var index = 0;
foreach (var entry in Model.Roles) {
if (string.Equals(entry.Name, "Authenticated", StringComparison.OrdinalIgnoreCase) || string.Equals(entry.Name, "Anonymous", StringComparison.OrdinalIgnoreCase)) {
if (SystemRoles.GetSystemRoles().Contains(entry.Name)) {
continue;
}
@Html.Hidden("Roles[" + index + "].RoleId", entry.RoleId)
@Html.Hidden("Roles[" + index + "].Name", entry.Name)
<div>
@Html.CheckBox("Roles[" + index + "].Granted", entry.Granted)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Roles[index].Granted)">@entry.Name</label>
</div>
<div>
@Html.CheckBox("Roles[" + index + "].Granted", entry.Granted)
<label class="forcheckbox" for="@Html.FieldIdFor(m => m.Roles[index].Granted)">@entry.Name</label>
</div>
index++;
}
}
else {
<p>@T("There are no roles.")</p>
<p>@T("There are no roles.")</p>
}
</fieldset>