- Permissions system for Orchard.

- Add PermissionProviders to existing modules (CmsPages and Media)
- Roles and Permissions management in the admin.

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4039724
This commit is contained in:
suhacan
2009-11-12 00:40:40 +00:00
parent 2f5e08bc6c
commit 3758379324
13 changed files with 228 additions and 43 deletions

View File

@@ -0,0 +1,38 @@
using System.Collections.Generic;
using Orchard.Security.Permissions;
namespace Orchard.CmsPages {
public class CmsPagesPermissionsProvider : IPermissionProvider {
public static readonly Permission ViewPagesPermission = new Permission { Description = "Viewing CMS Pages", Name = "ViewCmsPagesPermission" };
public static readonly Permission CreatePagesPermission = new Permission { Description = "Creating CMS Pages", Name = "CreateCmsPagesPermission" };
public static readonly Permission CreateDraftPagesPermission = new Permission { Description = "Creating CMS Page Drafts", Name = "CreateDraftCmsPagesPermission" };
public static readonly Permission ModifyPagesPermission = new Permission { Description = "Modifying CMS Pages", Name = "ModifyCmsPagesPermission" };
public static readonly Permission DeletePagesPermission = new Permission { Description = "Deleting CMS Pages", Name = "DeleteCmsPagesPermission" };
public static readonly Permission PublishPagesPermission = new Permission { Description = "Publishing CMS Pages", Name = "PublishCmsPagesPermission" };
public static readonly Permission UnpublishPagesPermission = new Permission { Description = "Unpublishing CMS Pages", Name = "UnpublishCmsPagesPermission" };
public static readonly Permission SchedulePagesPermission = new Permission { Description = "Scheduling CMS Pages", Name = "ScheduleCmsPagesPermission" };
#region Implementation of IPermissionProvider
public string PackageName {
get {
return "CmsPages";
}
}
public IEnumerable<Permission> GetPermissions() {
return new List<Permission> {
ViewPagesPermission,
CreatePagesPermission,
CreateDraftPagesPermission,
ModifyPagesPermission,
DeletePagesPermission,
PublishPagesPermission,
UnpublishPagesPermission,
SchedulePagesPermission
};
}
#endregion
}
}

View File

@@ -69,6 +69,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="CmsPagesPermissions.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\TemplatesController.cs" />
<Compile Include="Models\ContentItem.cs" />

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using Orchard.Security.Permissions;
namespace Orchard.Media {
public class MediaPermissionsProvider : IPermissionProvider {
public static readonly Permission UploadMediaPermission = new Permission { Description = "Uploading Media Files", Name = "UploadMediaPermission" };
public static readonly Permission ModifyMediaPermission = new Permission { Description = "Modifying Media Files", Name = "ModifyMediaPermission" };
public static readonly Permission DeleteMediaPermission = new Permission { Description = "Deleting Media Files", Name = "DeleteMediaPermission" };
public static readonly Permission CreateMediaFolderPermission = new Permission { Description = "Creating Media Folders", Name = "CreateMediaFolderPermission" };
public static readonly Permission DeleteMediaFolderPermission = new Permission { Description = "Deleting Media Folders", Name = "DeleteMediaFolderPermission" };
public static readonly Permission RenameMediaFolderPermission = new Permission { Description = "Renaming Media Folders", Name = "RenameMediaFolderPermission" };
#region Implementation of IPermissionProvider
public string PackageName {
get {
return "Media";
}
}
public IEnumerable<Permission> GetPermissions() {
return new List<Permission> {
UploadMediaPermission,
ModifyMediaPermission,
DeleteMediaPermission,
CreateMediaFolderPermission,
DeleteMediaFolderPermission,
RenameMediaFolderPermission
};
}
#endregion
}
}

View File

@@ -72,6 +72,7 @@
<Compile Include="AdminMenu.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Helpers\MediaHelpers.cs" />
<Compile Include="MediaPermissions.cs" />
<Compile Include="Models\FolderNavigation.cs" />
<Compile Include="Models\MediaFile.cs" />
<Compile Include="Models\MediaFolder.cs" />

View File

@@ -42,7 +42,7 @@ namespace Orchard.Roles.Controllers {
}
public ActionResult Create() {
var model = new RoleCreateViewModel();
var model = new RoleCreateViewModel { PackagePermissions = _roleService.GetInstalledPermissions() };
return View(model);
}
@@ -52,11 +52,18 @@ namespace Orchard.Roles.Controllers {
try {
UpdateModel(viewModel, input.ToValueProvider());
_roleService.CreateRole(viewModel.Name);
foreach (string key in input.Keys) {
if (key.StartsWith("Checkbox.") && input[key] == "true") {
string permissionName = key.Substring("Checkbox.".Length);
_roleService.CreatePermissionForRole(viewModel.Name,
permissionName);
}
}
return RedirectToAction("Index");
}
catch (Exception exception) {
_notifier.Error("Creating Role failed: " + exception.Message);
return View(viewModel);
return RedirectToAction("Create");
}
}
@@ -66,7 +73,9 @@ namespace Orchard.Roles.Controllers {
//TODO: Error message
throw new HttpException(404, "page with id " + id + " was not found");
}
var model = new RoleEditViewModel { Name = role.Name, Id = role.Id };
var model = new RoleEditViewModel { Name = role.Name, Id = role.Id,
PackagePermissions = _roleService.GetInstalledPermissions(),
CurrentPermissions = _roleService.GetPermissionsForRole(id)};
return View(model);
}
@@ -78,7 +87,14 @@ namespace Orchard.Roles.Controllers {
UpdateModel(viewModel, input.ToValueProvider());
// Save
if (!String.IsNullOrEmpty(HttpContext.Request.Form["submit.Save"])) {
_roleService.UpdateRole(viewModel.Id, viewModel.Name);
List<string> rolePermissions = new List<string>();
foreach (string key in input.Keys) {
if (key.StartsWith("Checkbox.") && input[key] == "true") {
string permissionName = key.Substring("Checkbox.".Length);
rolePermissions.Add(permissionName);
}
}
_roleService.UpdateRole(viewModel.Id, viewModel.Name, rolePermissions);
}
else if (!String.IsNullOrEmpty(HttpContext.Request.Form["submit.Delete"])) {
_roleService.DeleteRole(viewModel.Id);
@@ -86,8 +102,8 @@ namespace Orchard.Roles.Controllers {
return RedirectToAction("Index");
}
catch (Exception exception) {
_notifier.Error("Editing media file failed: " + exception.Message);
return View(viewModel);
_notifier.Error("Editing Role failed: " + exception.Message);
return RedirectToAction("Edit", viewModel.Id);
}
}
}

View File

@@ -2,6 +2,7 @@
public class PermissionRecord {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string PackageName { get; set; }
public virtual string Description { get; set; }
}
}

View File

@@ -1,6 +1,16 @@
namespace Orchard.Roles.Models {
using System.Collections.Generic;
using Orchard.Data.Conventions;
namespace Orchard.Roles.Models {
public class RoleRecord {
public RoleRecord() {
RolesPermissions = new List<RolesPermissions>();
}
public virtual int Id { get; set; }
public virtual string Name { get; set; }
[CascadeAllDeleteOrphan]
public virtual IList<RolesPermissions> RolesPermissions { get; set; }
}
}

View File

@@ -4,21 +4,31 @@ using System.Linq;
using Orchard.Data;
using Orchard.Logging;
using Orchard.Roles.Models;
using Orchard.Security.Permissions;
namespace Orchard.Roles.Services {
public interface IRoleService : IDependency {
IEnumerable<RoleRecord> GetRoles();
RoleRecord GetRole(int id);
void CreateRole(string roleName);
void UpdateRole(int id, string roleName);
void CreatePermissionForRole(string roleName, string permissionName);
void UpdateRole(int id, string roleName, IEnumerable<string> rolePermissions);
void DeleteRole(int id);
IDictionary<string, IEnumerable<Permission>> GetInstalledPermissions();
IEnumerable<string> GetPermissionsForRole(int id);
}
public class RoleService : IRoleService {
private readonly IRepository<RoleRecord> _roleRepository;
private readonly IRepository<PermissionRecord> _permissionRepository;
private readonly IEnumerable<IPermissionProvider> _permissionProviders;
public RoleService(IRepository<RoleRecord> roleRepository) {
public RoleService(IRepository<RoleRecord> roleRepository,
IRepository<PermissionRecord> permissionRepository,
IEnumerable<IPermissionProvider> permissionProviders) {
_roleRepository = roleRepository;
_permissionRepository = permissionRepository;
_permissionProviders = permissionProviders;
Logger = NullLogger.Instance;
}
@@ -39,12 +49,80 @@ namespace Orchard.Roles.Services {
_roleRepository.Create(new RoleRecord { Name = roleName });
}
public void UpdateRole(int id, string roleName) {
_roleRepository.Update(new RoleRecord { Id = id, Name = roleName });
public void CreatePermissionForRole(string roleName, string permissionName) {
if (_permissionRepository.Get(x => x.Name == permissionName) == null) {
_permissionRepository.Create(new PermissionRecord {
Description = GetPermissionDescription(permissionName),
Name = permissionName,
PackageName = GetPackageName(permissionName)
});
}
RoleRecord roleRecord = _roleRepository.Get(x => x.Name == roleName);
PermissionRecord permissionRecord = _permissionRepository.Get(x => x.Name == permissionName);
roleRecord.RolesPermissions.Add(new RolesPermissions { Permission = permissionRecord, Role = roleRecord });
}
public void UpdateRole(int id, string roleName, IEnumerable<string> rolePermissions) {
RoleRecord roleRecord = GetRole(id);
roleRecord.Name = roleName;
roleRecord.RolesPermissions.Clear();
foreach (var rolePermission in rolePermissions) {
string permission = rolePermission;
if (_permissionRepository.Get(x => x.Name == permission) == null) {
_permissionRepository.Create(new PermissionRecord {
Description = GetPermissionDescription(permission),
Name = permission,
PackageName = GetPackageName(permission)
});
}
PermissionRecord permissionRecord = _permissionRepository.Get(x => x.Name == permission);
roleRecord.RolesPermissions.Add(new RolesPermissions { Permission = permissionRecord, Role = roleRecord });
}
}
private string GetPackageName(string permissionName) {
foreach (var permissionProvider in _permissionProviders) {
foreach (var permission in permissionProvider.GetPermissions()) {
if (String.Equals(permissionName, permission.Name, StringComparison.OrdinalIgnoreCase)) {
return permissionProvider.PackageName;
}
}
}
throw new ArgumentException("Permission " + permissionName + " was not found in any of the installed packages.");
}
private string GetPermissionDescription(string permissionName) {
foreach (var permissionProvider in _permissionProviders) {
foreach (var permission in permissionProvider.GetPermissions()) {
if (String.Equals(permissionName, permission.Name, StringComparison.OrdinalIgnoreCase)) {
return permission.Description;
}
}
}
throw new ArgumentException("Permission " + permissionName + " was not found in any of the installed packages.");
}
public void DeleteRole(int id) {
_roleRepository.Delete(new RoleRecord { Id = id });
_roleRepository.Delete(GetRole(id));
}
public IDictionary<string, IEnumerable<Permission>> GetInstalledPermissions() {
Dictionary<string, IEnumerable<Permission>> installedPermissions = new Dictionary<string, IEnumerable<Permission>>();
foreach (var permissionProvider in _permissionProviders) {
IEnumerable<Permission> permissions = permissionProvider.GetPermissions();
installedPermissions.Add(permissionProvider.PackageName, permissions);
}
return installedPermissions;
}
public IEnumerable<string> GetPermissionsForRole(int id) {
List<string> permissions = new List<string>();
RoleRecord roleRecord = GetRole(id);
foreach (RolesPermissions rolesPermission in roleRecord.RolesPermissions) {
permissions.Add(rolesPermission.Permission.Name);
}
return permissions;
}
#endregion

View File

@@ -1,9 +1,12 @@
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Orchard.Mvc.ViewModels;
using Orchard.Security.Permissions;
namespace Orchard.Roles.ViewModels {
public class RoleCreateViewModel : AdminViewModel {
[Required]
public string Name { get; set; }
public IDictionary<string, IEnumerable<Permission>> PackagePermissions { get; set; }
}
}

View File

@@ -1,10 +1,14 @@
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Orchard.Mvc.ViewModels;
using Orchard.Security.Permissions;
namespace Orchard.Roles.ViewModels {
public class RoleEditViewModel : AdminViewModel {
public int Id { get; set; }
[Required]
public string Name { get; set; }
public IDictionary<string, IEnumerable<Permission>> PackagePermissions { get; set; }
public IEnumerable<string> CurrentPermissions { get; set; }
}
}

View File

@@ -19,8 +19,8 @@
<input id="Name" class="inputText inputTextLarge" name="Name" type="text" value="<%= Model.Name %>" />
<h3>Permissions</h3>
<h4>Pages Module</h4>
<% foreach (var packageName in Model.PackagePermissions.Keys) { %>
<h4><%= packageName %> Module</h4>
<table id="pluginListTable" cellspacing="0" class="roundCorners clearLayout" >
<colgroup>
<col id="Permission" />
@@ -32,19 +32,16 @@
<th scope="col">Allow</th>
</tr>
</thead>
<tr>
<td>View pages</td>
<td><input type="checkbox" value="" /></td>
</tr>
<tr>
<td>Create draft pages</td>
<td><input type="checkbox" value="" /></td>
</tr>
<tr>
<td>Edit any page</td>
<td><input type="checkbox" value="" /></td>
<% foreach (var permission in Model.PackagePermissions[packageName]) {%>
<tr>
<td><%=permission.Description%></td>
<td>
<input type="checkbox" value="true" name="<%="Checkbox." + permission.Name%>"/>
</td>
</tr>
<% } %>
</table>
<% } %>
<input type="submit" class="button" value="Save" />
</div>
<% Html.EndForm(); %>

View File

@@ -20,11 +20,12 @@
<input type="hidden" value="<%= Model.Id %>" name="Id" />
<h3>Permissions</h3>
<h4>Pages Module</h4>
<table id="pluginListTable" cellspacing="0" class="roundCorners clearLayout" >
<% foreach (var packageName in Model.PackagePermissions.Keys) { %>
<h4><%= packageName %> Module</h4>
<table id="Table1" cellspacing="0" class="roundCorners clearLayout" >
<colgroup>
<col id="Permission" />
<col id="Allow" />
<col id="Col1" />
<col id="Col2" />
</colgroup>
<thead>
<tr>
@@ -32,19 +33,20 @@
<th scope="col">Allow</th>
</tr>
</thead>
<tr>
<td>View pages</td>
<td><input type="checkbox" value="" /></td>
</tr>
<tr>
<td>Create draft pages</td>
<td><input type="checkbox" value="" /></td>
</tr>
<tr>
<td>Edit any page</td>
<td><input type="checkbox" value="" /></td>
<% foreach (var permission in Model.PackagePermissions[packageName]) {%>
<tr>
<td><%=permission.Description%></td>
<td>
<% if (Model.CurrentPermissions.Contains(permission.Name)) {%>
<input type="checkbox" value="true" name="<%="Checkbox." + permission.Name%>" checked="checked"/>
<% } else {%>
<input type="checkbox" value="true" name="<%="Checkbox." + permission.Name%>"/>
<% }%>
</td>
</tr>
<% } %>
</table>
<% } %>
<input type="submit" class="button" name="submit.Save" value="Save" />
<input type="submit" class="button" name="submit.Delete" value="Delete" />
</div>

View File

@@ -5,7 +5,7 @@ namespace Orchard.Security.Permissions {
/// Implemented by packages to enumerate the types of permissions
/// the which may be granted
/// </summary>
public interface IPermissionProvider {
public interface IPermissionProvider : IDependency {
string PackageName { get; }
IEnumerable<Permission> GetPermissions();
}