Updating security processing. Adding a base for an OrchardException hierarchy.

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4045830
This commit is contained in:
loudej
2010-01-22 06:32:54 +00:00
parent c455394cc2
commit 7f09516e8c
20 changed files with 88 additions and 32 deletions

View File

@@ -19,7 +19,10 @@ namespace Orchard.Tests.UI.Navigation {
} }
public class StubAuth : IAuthorizationService { public class StubAuth : IAuthorizationService {
public bool CheckAccess(IUser user, Permission permission) { public void CheckAccess(IUser user, Permission permission) {
}
public bool TryCheckAccess(IUser user, Permission permission) {
return true; return true;
} }
} }

View File

@@ -134,7 +134,7 @@ namespace Orchard.Core.Common.Providers {
private void GetEditor(BuildEditorModelContext context, CommonAspect instance) { private void GetEditor(BuildEditorModelContext context, CommonAspect instance) {
var currentUser = _authenticationService.GetAuthenticatedUser(); var currentUser = _authenticationService.GetAuthenticatedUser();
if (!_authorizationService.CheckAccess(currentUser, Permissions.ChangeOwner)) { if (!_authorizationService.TryCheckAccess(currentUser, Permissions.ChangeOwner)) {
return; return;
} }
var viewModel = new OwnerEditorViewModel(); var viewModel = new OwnerEditorViewModel();
@@ -152,7 +152,7 @@ namespace Orchard.Core.Common.Providers {
instance.VersionModifiedUtc = _clock.UtcNow; instance.VersionModifiedUtc = _clock.UtcNow;
var currentUser = _authenticationService.GetAuthenticatedUser(); var currentUser = _authenticationService.GetAuthenticatedUser();
if (!_authorizationService.CheckAccess(currentUser, Permissions.ChangeOwner)) { if (!_authorizationService.TryCheckAccess(currentUser, Permissions.ChangeOwner)) {
return; return;
} }

View File

@@ -4,7 +4,6 @@ Html.RegisterStyle("site.css");
Model.Zones.AddRenderPartial("header", "header", Model); Model.Zones.AddRenderPartial("header", "header", Model);
Model.Zones.AddRenderPartial("header:after", "user", Model); Model.Zones.AddRenderPartial("header:after", "user", Model);
Model.Zones.AddRenderPartial("menu", "menu", Model); Model.Zones.AddRenderPartial("menu", "menu", Model);
Model.Zones.AddRenderPartial("content:before", "messages", Model.Messages);
%> %>
<div id="page"> <div id="page">
<div id="header"><% <div id="header"><%

View File

@@ -46,7 +46,7 @@ namespace Orchard.Media.Services {
XRpcStruct file) { XRpcStruct file) {
var user = _membershipService.ValidateUser(userName, password); var user = _membershipService.ValidateUser(userName, password);
if (!_authorizationService.CheckAccess(user, Permissions.UploadMediaFiles)) { if (!_authorizationService.TryCheckAccess(user, Permissions.UploadMediaFiles)) {
//TEMP: return appropriate access-denied response for user //TEMP: return appropriate access-denied response for user
throw new ApplicationException("Access denied"); throw new ApplicationException("Access denied");
} }

View File

@@ -111,7 +111,7 @@ namespace Orchard.Roles.Controllers {
var simulation = UserSimulation.Create(role.Name); var simulation = UserSimulation.Create(role.Name);
model.EffectivePermissions = model.PackagePermissions model.EffectivePermissions = model.PackagePermissions
.SelectMany(group => group.Value) .SelectMany(group => group.Value)
.Where(permission => _authorizationService.CheckAccess(simulation, permission)) .Where(permission => _authorizationService.TryCheckAccess(simulation, permission))
.Select(permission=>permission.Name) .Select(permission=>permission.Name)
.Distinct() .Distinct()
.ToList(); .ToList();

View File

@@ -40,7 +40,7 @@ namespace Orchard.Roles.Controllers {
protected override DriverResult Editor(UserRoles userRoles) { protected override DriverResult Editor(UserRoles userRoles) {
// don't show editor without apply roles permission // don't show editor without apply roles permission
if (!_authorizationService.CheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles)) if (!_authorizationService.TryCheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles))
return null; return null;
var roles = var roles =
@@ -61,7 +61,7 @@ namespace Orchard.Roles.Controllers {
protected override DriverResult Editor(UserRoles userRoles, IUpdateModel updater) { protected override DriverResult Editor(UserRoles userRoles, IUpdateModel updater) {
// don't apply editor without apply roles permission // don't apply editor without apply roles permission
if (!_authorizationService.CheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles)) if (!_authorizationService.TryCheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles))
return null; return null;
var model = new UserRolesViewModel { var model = new UserRolesViewModel {

View File

@@ -24,7 +24,13 @@ namespace Orchard.Roles.Services {
#region Implementation of IAuthorizationService #region Implementation of IAuthorizationService
public bool CheckAccess(IUser user, Permission permission) { public void CheckAccess(IUser user, Permission permission) {
if (!TryCheckAccess(user, permission)) {
throw new OrchardSecurityException { PermissionName = permission.Name };
}
}
public bool TryCheckAccess(IUser user, Permission permission) {
if (user == null) { if (user == null) {
return false; return false;
} }

View File

@@ -28,7 +28,7 @@ namespace Orchard.Tags.Controllers {
} }
protected override DriverResult Editor(HasTags part) { protected override DriverResult Editor(HasTags part) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag)) if (!_authorizationService.TryCheckAccess(CurrentUser, Permissions.ApplyTag))
return null; return null;
var model = new EditTagsViewModel { var model = new EditTagsViewModel {
@@ -38,7 +38,7 @@ namespace Orchard.Tags.Controllers {
} }
protected override DriverResult Editor(HasTags part, IUpdateModel updater) { protected override DriverResult Editor(HasTags part, IUpdateModel updater) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag)) if (!_authorizationService.TryCheckAccess(CurrentUser, Permissions.ApplyTag))
return null; return null;
var model = new EditTagsViewModel(); var model = new EditTagsViewModel();

View File

@@ -66,8 +66,7 @@ namespace Orchard.Tags.Services {
public void CreateTag(string tagName) { public void CreateTag(string tagName) {
if (_tagRepository.Get(x => x.TagName == tagName) == null) { if (_tagRepository.Get(x => x.TagName == tagName) == null) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.CreateTag)) _authorizationService.CheckAccess(CurrentUser, Permissions.CreateTag);
throw new UnauthorizedException();
Tag tag = new Tag { TagName = tagName }; Tag tag = new Tag { TagName = tagName };
_tagRepository.Create(tag); _tagRepository.Create(tag);
@@ -130,8 +129,7 @@ namespace Orchard.Tags.Services {
foreach (var tagContentItem in currentTagsForContentItem) { foreach (var tagContentItem in currentTagsForContentItem) {
if (!newTagsForContentItem.Contains(tagContentItem.TagId)) { if (!newTagsForContentItem.Contains(tagContentItem.TagId)) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag)) _authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag);
throw new UnauthorizedException();
_tagsContentItemsRepository.Delete(tagContentItem); _tagsContentItemsRepository.Delete(tagContentItem);
} }
@@ -141,8 +139,7 @@ namespace Orchard.Tags.Services {
} }
foreach (var newTagForContentItem in newTagsForContentItem) { foreach (var newTagForContentItem in newTagsForContentItem) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag)) _authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag);
throw new UnauthorizedException();
_tagsContentItemsRepository.Create(new TagsContentItems { ContentItemId = contentItemId, TagId = newTagForContentItem }); _tagsContentItemsRepository.Create(new TagsContentItems { ContentItemId = contentItemId, TagId = newTagForContentItem });
} }

View File

@@ -4,7 +4,6 @@ Html.RegisterStyle("site.css");
Model.Zones.AddRenderPartial("header", "header", Model); Model.Zones.AddRenderPartial("header", "header", Model);
Model.Zones.AddRenderPartial("header:after", "user", Model); Model.Zones.AddRenderPartial("header:after", "user", Model);
Model.Zones.AddRenderPartial("menu", "menu", Model); Model.Zones.AddRenderPartial("menu", "menu", Model);
Model.Zones.AddRenderPartial("content:before", "messages", Model.Messages);
%> %>
<div class="page"> <div class="page">
<div id="header"><% <div id="header"><%

View File

@@ -5,7 +5,6 @@ Html.RegisterStyle("site.css");
Model.Zones.AddRenderPartial("header", "header", Model); Model.Zones.AddRenderPartial("header", "header", Model);
Model.Zones.AddRenderPartial("header:after", "user", Model); // todo: (heskew) should be a user display or widget Model.Zones.AddRenderPartial("header:after", "user", Model); // todo: (heskew) should be a user display or widget
Model.Zones.AddRenderPartial("menu", "menu", Model); Model.Zones.AddRenderPartial("menu", "menu", Model);
Model.Zones.AddRenderPartial("content:before", "messages", Model.Messages);
%> %>
<div id="header" role="banner"><% Html.Zone("header"); %></div> <div id="header" role="banner"><% Html.Zone("header"); %></div>
<div id="content"> <div id="content">

View File

@@ -1,6 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading;
using Orchard.Logging; using Orchard.Logging;
using Orchard.Security;
namespace Orchard { namespace Orchard {
public interface IEvents : IDependency { public interface IEvents : IDependency {
@@ -27,12 +31,19 @@ namespace Orchard {
} }
} }
private static bool IsLogged(Exception exception) { private static bool IsLogged(Exception ex) {
return true; return ex is OrchardSecurityException || !IsFatal(ex);
} }
private static bool IsFatal(Exception exception) { private static bool IsFatal(Exception ex) {
return false; return ex is OrchardSecurityException ||
ex is StackOverflowException ||
ex is AccessViolationException ||
ex is AppDomainUnloadedException ||
ex is ExecutionEngineException ||
ex is ThreadAbortException ||
ex is SecurityException ||
ex is SEHException;
} }
} }
} }

View File

@@ -136,8 +136,9 @@
<Compile Include="Extensions\ExtensionFolders.cs" /> <Compile Include="Extensions\ExtensionFolders.cs" />
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" /> <Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />
<Compile Include="Extensions\UriExtensions.cs" /> <Compile Include="Extensions\UriExtensions.cs" />
<Compile Include="OrchardException.cs" />
<Compile Include="Security\StandardPermissions.cs" /> <Compile Include="Security\StandardPermissions.cs" />
<Compile Include="Security\UnauthorizedException.cs" /> <Compile Include="Security\OrchardSecurityException.cs" />
<Compile Include="Tasks\Scheduling\IScheduledTask.cs" /> <Compile Include="Tasks\Scheduling\IScheduledTask.cs" />
<Compile Include="ContentManagement\ContentExtensions.cs" /> <Compile Include="ContentManagement\ContentExtensions.cs" />
<Compile Include="ContentManagement\ContentItem.cs" /> <Compile Include="ContentManagement\ContentItem.cs" />

View File

@@ -0,0 +1,12 @@
using System;
using System.Runtime.Serialization;
namespace Orchard {
public class OrchardException : ApplicationException {
public OrchardException() : base("An exception occurred in the content management system.") { }
public OrchardException(Exception innerException) : base(innerException.Message, innerException) { }
public OrchardException(string message) : base(message) { }
protected OrchardException(SerializationInfo info, StreamingContext context) : base(info, context) { }
public OrchardException(string message, Exception innerException) : base(message, innerException) { }
}
}

View File

@@ -24,7 +24,7 @@ namespace Orchard.Security {
public Localizer T { get; set; } public Localizer T { get; set; }
public bool Authorize(Permission permission, LocalizedString message) { public bool Authorize(Permission permission, LocalizedString message) {
if (_authorizationService.CheckAccess(CurrentUser, permission)) if (_authorizationService.TryCheckAccess(CurrentUser, permission))
return true; return true;
if (CurrentUser == null) { if (CurrentUser == null) {

View File

@@ -6,6 +6,7 @@ namespace Orchard.Security {
/// provided by default. /// provided by default.
/// </summary> /// </summary>
public interface IAuthorizationService : IDependency { public interface IAuthorizationService : IDependency {
bool CheckAccess(IUser user, Permission permission); void CheckAccess(IUser user, Permission permission);
bool TryCheckAccess(IUser user, Permission permission);
} }
} }

View File

@@ -0,0 +1,14 @@
using System;
using System.Runtime.Serialization;
namespace Orchard.Security {
public class OrchardSecurityException : OrchardException {
public OrchardSecurityException() : base("A security exception occurred in the content management system.") { }
public OrchardSecurityException(Exception innerException) : base(innerException.Message, innerException) { }
public OrchardSecurityException(string message) : base(message) { }
protected OrchardSecurityException(SerializationInfo info, StreamingContext context) : base(info, context) { }
public OrchardSecurityException(string message, Exception innerException) : base(message, innerException) { }
public string PermissionName { get; set; }
}
}

View File

@@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using System.Web.Mvc; using System.Web.Mvc;
using JetBrains.Annotations; using JetBrains.Annotations;
using Orchard.Logging;
using Orchard.Mvc.Filters; using Orchard.Mvc.Filters;
using Orchard.Mvc.ViewModels; using Orchard.Mvc.ViewModels;
@@ -12,8 +13,11 @@ namespace Orchard.Security {
public SecurityFilter(IAuthenticationService authenticationService) { public SecurityFilter(IAuthenticationService authenticationService) {
_authenticationService = authenticationService; _authenticationService = authenticationService;
Logger = NullLogger.Instance;
} }
public ILogger Logger { get; set; }
public void OnResultExecuting(ResultExecutingContext filterContext) { public void OnResultExecuting(ResultExecutingContext filterContext) {
var viewResult = filterContext.Result as ViewResultBase; var viewResult = filterContext.Result as ViewResultBase;
if (viewResult == null) if (viewResult == null)
@@ -32,10 +36,19 @@ namespace Orchard.Security {
} }
public void OnException(ExceptionContext filterContext) { public void OnException(ExceptionContext filterContext) {
if (filterContext.Exception is UnauthorizedException) { if (!(filterContext.Exception is OrchardSecurityException)) {
return;
}
try {
Logger.Information(filterContext.Exception, "Security exception converted to access denied result");
}
catch {
//a logger exception can't be allowed to interrupt this process
}
filterContext.Result = new HttpUnauthorizedResult(); filterContext.Result = new HttpUnauthorizedResult();
filterContext.ExceptionHandled = true; filterContext.ExceptionHandled = true;
} }
} }
}
} }

View File

@@ -27,11 +27,11 @@ namespace Orchard.UI.Navigation {
} }
private IEnumerable<MenuItem> Reduce(IEnumerable<MenuItem> items) { private IEnumerable<MenuItem> Reduce(IEnumerable<MenuItem> items) {
var hasDebugShowAllMenuItems = _authorizationService.CheckAccess(CurrentUser, Permission.Named("DebugShowAllMenuItems")); var hasDebugShowAllMenuItems = _authorizationService.TryCheckAccess(CurrentUser, Permission.Named("DebugShowAllMenuItems"));
foreach (var item in items) { foreach (var item in items) {
if (hasDebugShowAllMenuItems || if (hasDebugShowAllMenuItems ||
!item.Permissions.Any() || !item.Permissions.Any() ||
item.Permissions.Any(x => _authorizationService.CheckAccess(CurrentUser, x))) { item.Permissions.Any(x => _authorizationService.TryCheckAccess(CurrentUser, x))) {
yield return new MenuItem { yield return new MenuItem {
Items = Reduce(item.Items), Items = Reduce(item.Items),
Permissions = item.Permissions, Permissions = item.Permissions,

View File

@@ -81,6 +81,7 @@ namespace Orchard.UI.Notify {
} }
baseViewModel.Messages = baseViewModel.Messages == null ? messageEntries : baseViewModel.Messages.Union(messageEntries).ToList(); baseViewModel.Messages = baseViewModel.Messages == null ? messageEntries : baseViewModel.Messages.Union(messageEntries).ToList();
baseViewModel.Zones.AddRenderPartial("content:before", "Messages", baseViewModel.Messages);
} }
public void OnResultExecuted(ResultExecutedContext filterContext) { public void OnResultExecuted(ResultExecutedContext filterContext) {