Secures all ITasks, adds unit tests to ensure they are all secured and the correct app is assigned.
This commit is contained in:
92
src/Umbraco.Web/UI/LegacyDialogTask.cs
Normal file
92
src/Umbraco.Web/UI/LegacyDialogTask.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Authentication;
|
||||
using System.Text;
|
||||
using Umbraco.Core;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.businesslogic.Exceptions;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// An abstract class that is used to implement all secure ITasks
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In the near future we will overhaul how create dialogs work and how deletions work as well. In the meantime
|
||||
/// if you ever need to create an ITask you should just inherit from this class and do not manually implement
|
||||
/// ITask or ITaskReturnUrl. If you do, you MUST also implement IAppTask which associates an ITask to an app
|
||||
/// so we can validate the current user's security with the implementation. If you do not do this then your
|
||||
/// implementation will not be secure. It means that if someone is logged in and doesn't have access to a
|
||||
/// specific app, they'd still be able to execute code to create/delete for any ITask regardless of what app
|
||||
/// they have access to.
|
||||
/// </remarks>
|
||||
public abstract class LegacyDialogTask : ITaskReturnUrl, IAssignedApp
|
||||
{
|
||||
public virtual int ParentID { get; set; }
|
||||
public int TypeID { get; set; }
|
||||
public string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base class first performs authentication for the current app before proceeding
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Save()
|
||||
{
|
||||
if (ValidateUserForApplication())
|
||||
{
|
||||
return PerformSave();
|
||||
}
|
||||
throw new AuthenticationException("The current user does not have access to the required application that this task belongs to");
|
||||
}
|
||||
|
||||
public abstract bool PerformSave();
|
||||
|
||||
/// <summary>
|
||||
/// Base class first performs authentication for the current app before proceeding
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool Delete()
|
||||
{
|
||||
if (ValidateUserForApplication())
|
||||
{
|
||||
return PerformDelete();
|
||||
}
|
||||
throw new AuthenticationException("The current user does not have access to the required application that this task belongs to");
|
||||
}
|
||||
|
||||
public abstract bool PerformDelete();
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the user object for this Task
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// accessible by inheritors but can only be set internally
|
||||
/// </remarks>
|
||||
protected internal User User { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Implemented explicitly as we don't want to expose this
|
||||
/// </summary>
|
||||
int ITask.UserId
|
||||
{
|
||||
set { User = User.GetUser(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the currently assigned user has access to the assigned app
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected internal bool ValidateUserForApplication()
|
||||
{
|
||||
if (User == null)
|
||||
throw new InvalidOperationException("Cannot authenticate, no User object assigned");
|
||||
|
||||
return User.Applications.Any(app => app.alias.InvariantEquals(AssignedApp));
|
||||
}
|
||||
|
||||
public abstract string ReturnUrl { get; }
|
||||
public abstract string AssignedApp { get; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user