using System;
using System.Data;
using System.Collections;
using System.Security.Principal;
using System.Threading;
using CMS.CMSHelper;
using CMS.DataEngine;
using CMS.EventLog;
using CMS.GlobalHelper;
using CMS.LicenseProvider;
using CMS.SettingsProvider;
using CMS.SiteProvider;
using CMS.Synchronization;
using CMS.DocumentEngine;
using CMS.UIControls;
using CMS.ExtendedControls;
[RegisterTitle("content.ui.propertiessecurity")]
public partial class CMSModules_Content_CMSDesk_Properties_Security : CMSPropertiesPage
{
#region "Variables"
protected AclProvider mAclProvider = null;
private EventLogProvider mEventLog = null;
protected SiteInfo currentSite = null;
protected CurrentUserInfo currentUser = null;
protected bool inheritsPermissions = false;
protected string ipAddress = null;
protected string eventUrl = null;
protected static Hashtable mLogs = new Hashtable();
protected static Hashtable mErrors = new Hashtable();
protected static Hashtable mInfos = new Hashtable();
#endregion
#region "Properties"
///
/// Access control list provider.
///
public AclProvider AclProvider
{
get
{
return mAclProvider ?? (mAclProvider = new AclProvider(DocumentManager.Tree));
}
set
{
mAclProvider = value;
}
}
///
/// Document name.
///
protected string DocumentName
{
get
{
if (Node != null)
{
return Node.GetDocumentName();
}
return string.Empty;
}
}
///
/// Event log provider.
///
public EventLogProvider EventLog
{
get
{
return mEventLog ?? (mEventLog = new EventLogProvider());
}
}
///
/// Current log context.
///
public LogContext CurrentLog
{
get
{
return EnsureLog();
}
}
///
/// Current Error.
///
public string CurrentError
{
get
{
return ValidationHelper.GetString(mErrors["SyncError_" + ctlAsync.ProcessGUID], string.Empty);
}
set
{
mErrors["SyncError_" + ctlAsync.ProcessGUID] = value;
}
}
///
/// Current Info.
///
public string CurrentInfo
{
get
{
return ValidationHelper.GetString(mInfos["SyncInfo_" + ctlAsync.ProcessGUID], string.Empty);
}
set
{
mInfos["SyncInfo_" + ctlAsync.ProcessGUID] = value;
}
}
#endregion
#region "Page events"
protected override void OnInit(EventArgs e)
{
DocumentManager.OnCheckPermissions += DocumentManager_OnCheckPermissions;
DocumentManager.UseDocumentHelper = false;
securityElem.Node = Node;
securityElem.StopProcessing = pnlUIPermissionsPart.IsHidden;
securityElem.GroupID = Node.GetIntegerValue("NodeGroupID");
base.OnInit(e);
pnlAccessPart.Visible = !(pnlUIAuth.IsHidden && pnlUISsl.IsHidden);
if (!CMSContext.CurrentUser.IsAuthorizedPerUIElement("CMS.Content", "Properties.Security"))
{
RedirectToCMSDeskUIElementAccessDenied("CMS.Content", "Properties.Security");
}
// Redirect to information page when no UI elements displayed
if (pnlUIAuth.IsHidden && pnlUISsl.IsHidden && pnlUIPermissionsPart.IsHidden)
{
RedirectToUINotAvailable();
}
}
protected void DocumentManager_OnCheckPermissions(object sender, SimpleDocumentManagerEventArgs e)
{
e.CheckDefault = false;
e.ErrorMessage = String.Format(GetString("cmsdesk.notauthorizedtoeditdocumentpermissions"), e.Node.NodeAliasPath);
e.IsValid = CanModifyPermission(false, e.Node, currentUser);
}
protected void Page_Load(Object sender, EventArgs e)
{
currentSite = CMSContext.CurrentSite;
currentUser = CMSContext.CurrentUser;
ipAddress = HTTPHelper.UserHostAddress;
eventUrl = HTTPHelper.GetAbsoluteUri();
if (!RequestHelper.IsCallback())
{
btnCancel.Attributes.Add("onclick", ctlAsync.GetCancelScript(true) + "return false;");
btnCancel.Text = GetString("General.Cancel");
pnlLog.Visible = false;
pnlPageContent.Visible = true;
// Gets the node
if (Node != null)
{
UIContext.PropertyTab = PropertyTabEnum.Security;
// Check license
if (DataHelper.GetNotEmpty(URLHelper.GetCurrentDomain(), string.Empty) != string.Empty)
{
if (!LicenseKeyInfoProvider.IsFeatureAvailable(URLHelper.GetCurrentDomain(), FeatureEnum.DocumentLevelPermissions))
{
if (UIHelper.IsUnavailableUIHidden())
{
plcContainer.Visible = false;
}
else
{
pnlPermissions.Visible = false;
lblLicenseInfo.Visible = true;
lblLicenseInfo.Text = GetString("Security.NotAvailableInThisEdition");
}
}
}
// Initialize controls
SetupControls();
// Register scripts
ScriptHelper.RegisterDialogScript(this);
// Check if document inherits permissions and display info
inheritsPermissions = AclProvider.DoesNodeInheritPermissions(Node.NodeID);
lblInheritanceInfo.Text = inheritsPermissions ? GetString("Security.InheritsInfo.Inherits") : GetString("Security.InheritsInfo.DoesNotInherit");
if (!RequestHelper.IsPostBack())
{
// Set secured radio buttons
switch (Node.IsSecuredNode)
{
case 0:
radNo.Checked = true;
break;
case 1:
radYes.Checked = true;
break;
default:
if (Node.NodeParentID == 0)
{
radNo.Checked = true;
}
else
{
radParent.Checked = true;
}
break;
}
// Set secured radio buttons
switch (Node.RequiresSSL)
{
case 0:
radNoSSL.Checked = true;
break;
case 1:
radYesSSL.Checked = true;
break;
case 2:
radNeverSSL.Checked = true;
break;
default:
if (Node.NodeParentID == 0)
{
radNoSSL.Checked = true;
}
else
{
radParentSSL.Checked = true;
}
break;
}
}
// Hide link to the inheritance settings if this is the root node
if (Node.NodeParentID == 0)
{
plcAuthParent.Visible = false;
plcSSLParent.Visible = false;
lnkInheritance.Visible = false;
}
}
else
{
pnlPageContent.Visible = false;
}
}
ctlAsync.OnFinished += ctlAsync_OnFinished;
ctlAsync.OnError += ctlAsync_OnError;
ctlAsync.OnRequestLog += ctlAsync_OnRequestLog;
ctlAsync.OnCancel += ctlAsync_OnCancel;
pnlPageContent.Enabled = !DocumentManager.ProcessingAction;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
CheckModifyPermission(false);
if (pnlAccessPart.Visible)
{
pnlAccessPart.Visible = !(pnlUIAuth.IsHidden && pnlUISsl.IsHidden);
}
}
#endregion
#region "Methods"
///
/// Checks if current use can modify the permission.
///
/// If true and can't modify the user is redirected to denied page
private void CheckModifyPermission(bool redirect)
{
CanModifyPermission(redirect, Node, currentUser);
}
///
/// Checks if current use can modify the permission.
///
/// If true and can't modify the user is redirected to denied page
/// Current node
/// Current user
private bool CanModifyPermission(bool redirect, TreeNode currentNode, CurrentUserInfo user)
{
bool hasPermission = false;
if (currentNode != null)
{
hasPermission = (user.IsAuthorizedPerDocument(currentNode, NodePermissionsEnum.ModifyPermissions) == AuthorizationResultEnum.Allowed);
// If hasn't permission and redirect enabled
if (!hasPermission)
{
if (redirect)
{
RedirectToAccessDenied(String.Format(GetString("cmsdesk.notauthorizedtoeditdocumentpermissions"), currentNode.NodeAliasPath));
}
else
{
pnlAccessPart.Enabled = false;
btnRadOk.Enabled = false;
pnlInheritance.Enabled = false;
lnkInheritance.Visible = false;
}
}
}
return hasPermission;
}
///
/// Initializes components.
///
private void SetupControls()
{
// Set labels
pnlPermissionsPart.GroupingText = GetString("Security.Permissions");
pnlInheritance.GroupingText = GetString("Security.Permissions");
pnlAccessPart.GroupingText = GetString("Security.Access");
}
///
/// Switches back to default layout (after some action).
///
private void SwitchBackToPermissionsMode()
{
plcContainer.Visible = true;
pnlAccessPart.Visible = true;
pnlInheritance.Visible = false;
}
#endregion
#region "Events"
///
/// Displays inheritance settings.
///
protected void lnkInheritance_Click(Object sender, EventArgs e)
{
// Check permission
CheckModifyPermission(true);
plcContainer.Visible = false;
pnlAccessPart.Visible = false;
pnlInheritance.Visible = true;
// Test if current document inherits permissions
if (inheritsPermissions)
{
plcBreakClear.Visible = true;
plcBreakCopy.Visible = true;
plcRestore.Visible = false;
}
else
{
plcBreakClear.Visible = false;
plcBreakCopy.Visible = false;
plcRestore.Visible = true;
}
}
protected void btnCancelAction_Click(Object sender, EventArgs e)
{
SwitchBackToPermissionsMode();
}
protected void lnkBreakWithCopy_Click(Object sender, EventArgs e)
{
// Check permission
CheckModifyPermission(true);
// Break permission inheritance and copy parent permissions
AclProvider.BreakInherintance(Node, true);
// Log staging task
TaskParameters taskParam = new TaskParameters();
taskParam.SetParameter("copyPermissions", true);
DocumentSynchronizationHelper.LogDocumentChange(Node, TaskTypeEnum.BreakACLInheritance, Node.TreeProvider, SynchronizationInfoProvider.ENABLED_SERVERS, taskParam, Node.TreeProvider.AllowAsyncActions);
// Insert information about this event to event log.
if (DocumentManager.Tree.LogEvents)
{
EventLog.LogEvent(EventLogProvider.EVENT_TYPE_INFORMATION, DateTime.Now, "Content", "DOCPERMISSIONSMODIFIED", DocumentManager.Tree.UserInfo.UserID, DocumentManager.Tree.UserInfo.UserName, Node.NodeID, DocumentName, ipAddress, ResHelper.GetAPIString("security.documentpermissionsbreakcopy", "Inheritance of the parent document permissions have been broken. Parent document permissions have been copied."), Node.NodeSiteID, eventUrl);
}
lblInheritanceInfo.Text = GetString("Security.InheritsInfo.DoesNotInherit");
SwitchBackToPermissionsMode();
// Clear and reload
securityElem.InvalidateAcls();
securityElem.LoadOperators(true);
}
protected void lnkBreakWithClear_Click(Object sender, EventArgs e)
{
// Check permission
CheckModifyPermission(true);
// Break permission inheritance and clear permissions
AclProvider.BreakInherintance(Node, false);
// Log staging task and flush cache
DocumentSynchronizationHelper.LogDocumentChange(Node, TaskTypeEnum.BreakACLInheritance, Node.TreeProvider, SynchronizationInfoProvider.ENABLED_SERVERS, null, Node.TreeProvider.AllowAsyncActions);
CacheHelper.TouchKeys(TreeProvider.GetDependencyCacheKeys(Node, Node.NodeSiteName));
// Insert information about this event to event log.
if (DocumentManager.Tree.LogEvents)
{
EventLog.LogEvent(EventLogProvider.EVENT_TYPE_INFORMATION, DateTime.Now, "Content", "DOCPERMISSIONSMODIFIED", currentUser.UserID, currentUser.UserName, Node.NodeID, DocumentName, ipAddress, ResHelper.GetAPIString("security.documentpermissionsbreakclear", "Inheritance of the parent document permissions have been broken."), Node.NodeSiteID, eventUrl);
}
lblInheritanceInfo.Text = GetString("Security.InheritsInfo.DoesNotInherit");
SwitchBackToPermissionsMode();
// Clear and reload
securityElem.InvalidateAcls();
securityElem.LoadOperators(true);
}
protected void lnkRestoreInheritance_Click(Object sender, EventArgs e)
{
ResetNodePermission(currentSite.SiteName, Node.NodeAliasPath, false, currentUser, null);
lblInheritanceInfo.Text = GetString("Security.InheritsInfo.Inherits");
SwitchBackToPermissionsMode();
// Clear and reload
securityElem.InvalidateAcls();
securityElem.LoadOperators(true);
}
protected void lnkRestoreInheritanceRecursively_Click(object sender, EventArgs e)
{
// Setup design
pnlLog.Visible = true;
pnlPageContent.Visible = false;
titleElem.TitleText = GetString("cmsdesk.restoringpermissioninheritance");
titleElem.TitleImage = GetImageUrl("/CMSModules/CMS_Content/Properties/restoreinheritance.png");
CurrentLog.Close();
EnsureLog();
CurrentError = string.Empty;
CurrentInfo = string.Empty;
// Recursively
ctlAsync.Parameter = CMSContext.CurrentUser;
ctlAsync.RunAsync(ResetNodePermission, WindowsIdentity.GetCurrent());
lblInheritanceInfo.Text = GetString("Security.InheritsInfo.Inherits");
SwitchBackToPermissionsMode();
// Clear and reload
securityElem.InvalidateAcls();
securityElem.LoadOperators(true);
}
///
/// Async reset node action.
///
/// Accepts CurrentUserInfo
protected void ResetNodePermission(object parameter)
{
CurrentUserInfo user = parameter as CurrentUserInfo;
if (user != null)
{
// Add information to log
AddLog(GetString("cmsdesk.restoringpermissioninheritance"));
TreeProvider tr = new TreeProvider(user);
ResetNodePermission(currentSite.SiteName, Node.NodeAliasPath, true, user, tr);
}
}
///
/// Resets permission inheritance of node and its children.
///
/// Name of site
/// Alias path
/// Indicates whether to recursively reset all nodes below the current node
/// Current user
/// Tree provider
/// Whether TRUE if no permission conflict has occurred
private bool ResetNodePermission(string siteName, string nodeAliasPath, bool recursive, CurrentUserInfo user, TreeProvider tr)
{
// Check permissions
bool permissionsResult = false;
try
{
if (tr == null)
{
tr = new TreeProvider(user);
}
// Get node by alias path
TreeNode treeNode = tr.SelectSingleNode(siteName, nodeAliasPath, null, true, null, false);
permissionsResult = CanModifyPermission(!recursive, treeNode, user);
if (treeNode != null)
{
// If user has permissions
if (permissionsResult)
{
// Break inheritance of a node
if (!AclProvider.DoesNodeInheritPermissions(treeNode.NodeID))
{
// Restore inheritance of a node
AclProvider.RestoreInheritance(treeNode);
// Log current encoded alias path
AddLog(HTMLHelper.HTMLEncode(nodeAliasPath));
// Log staging task and flush cache
DocumentSynchronizationHelper.LogDocumentChange(treeNode, TaskTypeEnum.RestoreACLInheritance, treeNode.TreeProvider, SynchronizationInfoProvider.ENABLED_SERVERS, null, treeNode.TreeProvider.AllowAsyncActions);
CacheHelper.TouchKeys(TreeProvider.GetDependencyCacheKeys(Node, Node.NodeSiteName));
// Insert information about this event to event log.
if (DocumentManager.Tree.LogEvents)
{
if (recursive)
{
LogContext.LogEvent(EventLogProvider.EVENT_TYPE_INFORMATION, DateTime.Now, "Content", "DOCPERMISSIONSMODIFIED", user.UserID, user.UserName, treeNode.NodeID, treeNode.GetDocumentName(), ipAddress, string.Format(ResHelper.GetAPIString("security.documentpermissionsrestoredfordoc", "Permissions of document '{0}' have been restored to the parent document permissions."), nodeAliasPath), Node.NodeSiteID, null, null, null, null);
}
else
{
EventLog.LogEvent(EventLogProvider.EVENT_TYPE_INFORMATION, DateTime.Now, "Content", "DOCPERMISSIONSMODIFIED", user.UserID, user.UserName, treeNode.NodeID, treeNode.GetDocumentName(), ipAddress, ResHelper.GetAPIString("security.documentpermissionsrestored", "Permissions have been restored to the parent document permissions."), Node.NodeSiteID, eventUrl);
}
}
}
else
{
AddLog(string.Format(ResHelper.GetString("cmsdesk.skippingrestoring"), HTMLHelper.HTMLEncode(nodeAliasPath)));
}
}
// Recursively reset node inheritance
if (recursive)
{
// Get child nodes of current node
DataSet ds = DocumentManager.Tree.SelectNodes(siteName, treeNode.NodeAliasPath.TrimEnd('/') + "/%", TreeProvider.ALL_CULTURES, true, null, null, null, 1, false, -1, TreeProvider.SELECTNODES_REQUIRED_COLUMNS + ",NodeAliasPath");
if (!DataHelper.DataSourceIsEmpty(ds))
{
foreach (DataRow dr in ds.Tables[0].Rows)
{
string childNodeAliasPath = ValidationHelper.GetString(dr["NodeAliasPath"], string.Empty);
if (!string.IsNullOrEmpty(childNodeAliasPath))
{
bool tempPermissionsResult = ResetNodePermission(siteName, childNodeAliasPath, true, user, tr);
permissionsResult = tempPermissionsResult && permissionsResult;
}
}
}
}
}
}
catch (ThreadAbortException ex)
{
string state = ValidationHelper.GetString(ex.ExceptionState, string.Empty);
if (state == CMSThread.ABORT_REASON_STOP)
{
// When canceled
CurrentInfo = ResHelper.GetString("cmsdesk.restoringcanceled");
AddLog(CurrentInfo);
}
else
{
// Log error
CurrentError = ResHelper.GetString("cmsdesk.restoringfailed") + ": " + ex.Message;
AddLog(CurrentError);
}
}
catch (Exception ex)
{
// Log error
CurrentError = ResHelper.GetString("cmsdesk.restoringfailed") + ": " + ex.Message;
AddLog(CurrentError);
}
return permissionsResult;
}
///
/// On click OK save secured settings.
///
protected void btnRadOk_Click(object sender, EventArgs e)
{
// Check permission
CheckModifyPermission(true);
if (Node != null)
{
string message = null;
bool clearCache = false;
// Authentication
if (!pnlUIAuth.IsHidden)
{
int isSecuredNode = Node.IsSecuredNode;
if (radYes.Checked)
{
isSecuredNode = 1;
}
else if (radNo.Checked)
{
isSecuredNode = 0;
}
else if (radParent.Checked)
{
isSecuredNode = -1;
}
// Set secured areas settings
if (isSecuredNode != Node.IsSecuredNode)
{
Node.IsSecuredNode = isSecuredNode;
clearCache = true;
message += ResHelper.GetAPIString("security.documentaccessauthchanged", "Document authentication settings have been modified.");
}
}
// SSL
if (!pnlUISsl.IsHidden)
{
int requiresSSL = Node.RequiresSSL;
if (radYesSSL.Checked)
{
requiresSSL = 1;
}
else if (radNoSSL.Checked)
{
requiresSSL = 0;
}
else if (radParentSSL.Checked)
{
requiresSSL = -1;
}
else if (radNeverSSL.Checked)
{
requiresSSL = 2;
}
// Set SSL settings
if (requiresSSL != Node.RequiresSSL)
{
Node.RequiresSSL = requiresSSL;
clearCache = true;
if (message != null)
{
message += "
";
}
message += ResHelper.GetAPIString("security.documentaccesssslchanged", "Document SSL settings have been modified.");
}
}
DocumentManager.UpdateDocument(false);
DocumentManager.ClearContentChanged();
// Insert information about this event to event log.
if (DocumentManager.Tree.LogEvents && (message != null))
{
EventLog.LogEvent(EventLogProvider.EVENT_TYPE_INFORMATION, DateTime.Now, "Content", "DOCACCESSMODIFIED", currentUser.UserID, currentUser.UserName, Node.NodeID, DocumentName, ipAddress, message, Node.NodeSiteID, eventUrl);
}
// Clear cache if security settings changed
if (clearCache)
{
CacheHelper.ClearPageInfoCache(Node.NodeSiteName);
CacheHelper.ClearFileNodeCache(Node.NodeSiteName);
}
}
}
#endregion
#region "Async processing"
protected void ctlAsync_OnRequestLog(object sender, EventArgs e)
{
ctlAsync.Log = CurrentLog.Log;
}
protected void ctlAsync_OnError(object sender, EventArgs e)
{
CurrentLog.Close();
securityElem.LoadOperators(true);
securityElem.ErrorLabel.Text = CurrentError;
securityElem.InfoLabel.Text = CurrentInfo;
}
protected void ctlAsync_OnFinished(object sender, EventArgs e)
{
CurrentLog.Close();
securityElem.LoadOperators(true);
securityElem.ErrorLabel.Text = CurrentError;
securityElem.InfoLabel.Text = CurrentInfo;
}
protected void ctlAsync_OnCancel(object sender, EventArgs e)
{
CurrentLog.Close();
securityElem.LoadOperators(true);
securityElem.ErrorLabel.Text = CurrentError;
securityElem.InfoLabel.Text = CurrentInfo;
}
#endregion
#region "Log handling"
///
/// Adds the log information.
///
/// New log information
protected void AddLog(string newLog)
{
EnsureLog();
LogContext.AppendLine(newLog);
}
///
/// Adds the log error.
///
/// New log information
protected void AddErrorLog(string newLog)
{
AddErrorLog(newLog, null);
}
///
/// Adds the log error.
///
/// New log information
/// Error message
protected void AddErrorLog(string newLog, string errorMessage)
{
LogContext.AppendLine(newLog);
}
///
/// Ensures the logging context.
///
protected LogContext EnsureLog()
{
LogContext log = LogContext.EnsureLog(ctlAsync.ProcessGUID);
log.Reversed = true;
log.LineSeparator = "
";
return log;
}
#endregion
}