Fixes: U4-459 Public Access permissions not set on distributed servers

This commit is contained in:
Shannon
2014-03-27 16:11:34 +11:00
parent cde3c42cec
commit c309e18f13
8 changed files with 486 additions and 266 deletions

View File

@@ -139,9 +139,19 @@ namespace Umbraco.Web.Cache
//NOTE: we do not listen for the trashed event because there is no cache to update for content in that case since
// the unpublishing event handles that, and for examine with unpublished content indexes, we want to keep that data
// in the index, it's not until it's complete deleted that we want to remove it.
//public access events
Access.AfterSave += Access_AfterSave;
}
#region Public access event handlers
static void Access_AfterSave(Access sender, SaveEventArgs e)
{
DistributedCache.Instance.RefreshPublicAccess();
}
#endregion
#region Content service event handlers

View File

@@ -54,6 +54,7 @@ namespace Umbraco.Web.Cache
public const string StylesheetPropertyCacheRefresherId = "2BC7A3A4-6EB1-4FBC-BAA3-C9E7B6D36D38";
public const string DataTypeCacheRefresherId = "35B16C25-A17E-45D7-BC8F-EDAB1DCC28D2";
public const string DictionaryCacheRefresherId = "D1D7E227-F817-4816-BFE9-6C39B6152884";
public const string PublicAccessCacheRefresherId = "1DB08769-B104-4F8B-850E-169CAC1DF2EC";
#endregion
@@ -221,4 +222,4 @@ namespace Umbraco.Web.Cache
}
}
}
}

View File

@@ -13,6 +13,17 @@ namespace Umbraco.Web.Cache
/// </summary>
internal static class DistributedCacheExtensions
{
#region Public access
public static void RefreshPublicAccess(this DistributedCache dc)
{
dc.RefreshByJson(new Guid(DistributedCache.PublicAccessCacheRefresherId),
PublicAccessCacheRefresher.SerializeToJsonPayload(
Access.GetXmlDocumentCopy()));
}
#endregion
#region Application tree cache
public static void RefreshAllApplicationTreeCache(this DistributedCache dc)
{

View File

@@ -4,13 +4,13 @@ using System.Globalization;
using System.Web.Script.Serialization;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using umbraco.interfaces;
using System.Linq;
namespace Umbraco.Web.Cache
{
/// <summary>
/// A cache refresher to ensure media cache is updated
/// </summary>

View File

@@ -0,0 +1,77 @@
using System;
using System.Xml;
using Newtonsoft.Json;
using umbraco.cms.businesslogic.web;
using Umbraco.Core;
using Umbraco.Core.Cache;
namespace Umbraco.Web.Cache
{
public sealed class PublicAccessCacheRefresher : JsonCacheRefresherBase<PublicAccessCacheRefresher>
{
#region Static helpers
internal static JsonPayload DeserializeFromJsonPayload(string json)
{
return JsonConvert.DeserializeObject<JsonPayload>(json);
}
internal static string SerializeToJsonPayload(XmlDocument doc)
{
return JsonConvert.SerializeObject(FromXml(doc));
}
internal static JsonPayload FromXml(XmlDocument doc)
{
if (doc == null) return null;
var payload = new JsonPayload
{
XmlContent = doc.OuterXml
};
return payload;
}
#endregion
#region Sub classes
internal class JsonPayload
{
public string XmlContent { get; set; }
}
#endregion
protected override PublicAccessCacheRefresher Instance
{
get { return this; }
}
public override Guid UniqueIdentifier
{
get { return new Guid(DistributedCache.PublicAccessCacheRefresherId); }
}
public override string Name
{
get { return "Public access cache refresher"; }
}
public override void Refresh(string jsonPayload)
{
if (jsonPayload.IsNullOrWhiteSpace()) return;
var deserialized = DeserializeFromJsonPayload(jsonPayload);
if (deserialized == null) return;
var xDoc = new XmlDocument();
xDoc.LoadXml(deserialized.XmlContent);
ClearCache(xDoc);
base.Refresh(jsonPayload);
}
private void ClearCache(XmlDocument xDoc)
{
Access.UpdateInMemoryDocument(xDoc);
}
}
}

View File

@@ -285,6 +285,7 @@
<Compile Include="Cache\MemberCacheRefresher.cs" />
<Compile Include="Cache\MemberGroupCacheRefresher.cs" />
<Compile Include="Cache\PageCacheRefresher.cs" />
<Compile Include="Cache\PublicAccessCacheRefresher.cs" />
<Compile Include="Cache\StylesheetCacheRefresher.cs" />
<Compile Include="Cache\StylesheetPropertyCacheRefresher.cs" />
<Compile Include="Cache\TemplateCacheRefresher.cs" />

View File

@@ -96,7 +96,8 @@ namespace UmbracoExamine.DataServices
[SecuritySafeCritical]
private static XmlNode GetPage(int documentId)
{
var x = Access.AccessXml.SelectSingleNode("/access/page [@id=" + documentId.ToString() + "]");
var xDoc = Access.GetXmlDocumentCopy();
var x = xDoc.SelectSingleNode("/access/page [@id=" + documentId.ToString() + "]");
return x;
}

View File

@@ -1,11 +1,16 @@
using System;
using System.Data;
using System.Globalization;
using System.Threading;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Collections;
using System.IO;
using System.Web.Security;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Security;
@@ -18,98 +23,138 @@ namespace umbraco.cms.businesslogic.web
{
static private readonly Hashtable CheckedPages = new Hashtable();
//must be volatile for double check lock to work
static private volatile XmlDocument _accessXmlContent;
static private string _accessXmlSource;
private static void ClearCheckPages()
{
CheckedPages.Clear();
}
static readonly object Locko = new object();
static private string _accessXmlFilePath;
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
private static readonly object LoadLocker = new object();
[Obsolete("Do not access this property directly, it is not thread safe, use GetXmlDocumentCopy instead")]
public static XmlDocument AccessXml
{
get
get { return GetXmlDocument(); }
}
//private method to initialize and return the in-memory xmldocument
private static XmlDocument GetXmlDocument()
{
if (_accessXmlContent == null)
{
if (_accessXmlContent == null)
lock (LoadLocker)
{
lock (Locko)
if (_accessXmlContent == null)
{
if (_accessXmlContent == null)
if (_accessXmlFilePath == null)
{
if (_accessXmlSource == null)
{
//if we pop it here it'll make for better stack traces ;)
_accessXmlSource = IOHelper.MapPath(SystemFiles.AccessXml, true);
}
_accessXmlContent = new XmlDocument();
if (!System.IO.File.Exists(_accessXmlSource))
{
var file = new FileInfo(_accessXmlSource);
if (!Directory.Exists(file.DirectoryName))
{
Directory.CreateDirectory(file.Directory.FullName); //ensure the folder exists!
}
System.IO.FileStream f = System.IO.File.Open(_accessXmlSource, FileMode.Create);
System.IO.StreamWriter sw = new StreamWriter(f);
sw.WriteLine("<access/>");
sw.Close();
f.Close();
}
_accessXmlContent.Load(_accessXmlSource);
//if we pop it here it'll make for better stack traces ;)
_accessXmlFilePath = IOHelper.MapPath(SystemFiles.AccessXml);
}
_accessXmlContent = new XmlDocument();
if (File.Exists(_accessXmlFilePath) == false)
{
var file = new FileInfo(_accessXmlFilePath);
if (Directory.Exists(file.DirectoryName) == false)
{
Directory.CreateDirectory(file.Directory.FullName); //ensure the folder exists!
}
var f = File.Open(_accessXmlFilePath, FileMode.Create);
var sw = new StreamWriter(f);
sw.WriteLine("<access/>");
sw.Close();
f.Close();
}
_accessXmlContent.Load(_accessXmlFilePath);
}
}
return _accessXmlContent;
}
return _accessXmlContent;
}
//used by all other methods in this class to read and write the document which
// is thread safe and only clones once per request so it's still fast.
public static XmlDocument GetXmlDocumentCopy()
{
if (HttpContext.Current == null)
{
return (XmlDocument)GetXmlDocument().Clone();
}
if (HttpContext.Current.Items.Contains(typeof (Access)) == false)
{
HttpContext.Current.Items.Add(typeof (Access), GetXmlDocument().Clone());
}
return (XmlDocument)HttpContext.Current.Items[typeof(Access)];
}
#region Manipulation methods
public static void AddMembershipRoleToDocument(int documentId, string role)
{
//event
AddMemberShipRoleToDocumentEventArgs e = new AddMemberShipRoleToDocumentEventArgs();
var e = new AddMemberShipRoleToDocumentEventArgs();
new Access().FireBeforeAddMemberShipRoleToDocument(new Document(documentId), role, e);
if (!e.Cancel)
if (e.Cancel) return;
using (new WriteLock(Locker))
{
XmlElement x = (XmlElement)GetPage(documentId);
var x = (XmlElement)GetPage(documentId);
if (x == null)
throw new Exception("Document is not protected!");
else
{
if (x.SelectSingleNode("group [@id = '" + role + "']") == null)
{
XmlElement groupXml = (XmlElement)AccessXml.CreateNode(XmlNodeType.Element, "group", "");
groupXml.SetAttribute("id", role);
x.AppendChild(groupXml);
Save();
}
}
new Access().FireAfterAddMemberShipRoleToDocument(new Document(documentId), role, e);
if (x.SelectSingleNode("group [@id = '" + role + "']") == null)
{
var groupXml = (XmlElement)x.OwnerDocument.CreateNode(XmlNodeType.Element, "group", "");
groupXml.SetAttribute("id", role);
x.AppendChild(groupXml);
Save(x.OwnerDocument);
}
}
new Access().FireAfterAddMemberShipRoleToDocument(new Document(documentId), role, e);
}
/// <summary>
/// Used to refresh cache among servers in an LB scenario
/// </summary>
/// <param name="newDoc"></param>
internal static void UpdateInMemoryDocument(XmlDocument newDoc)
{
//NOTE: This would be better to use our normal ReaderWriter lock but because we are emitting an
// event inside of the WriteLock and code can then listen to the event and call this method we end
// up in a dead-lock. This specifically happens in the PublicAccessCacheRefresher.
//So instead we use the load locker which is what is used for the static XmlDocument instance, we'll
// lock that, set the doc to null which will cause any reader threads to block for the AccessXml instance
// then save the doc and re-load it, then all blocked threads can carry on.
lock (LoadLocker)
{
_accessXmlContent = null;
//do a real clone
_accessXmlContent = new XmlDocument();
_accessXmlContent.LoadXml(newDoc.OuterXml);
ClearCheckPages();
}
}
[Obsolete("This method is no longer supported. Use the ASP.NET MemberShip methods instead", true)]
public static void AddMemberGroupToDocument(int DocumentId, int MemberGroupId)
{
XmlElement x = (XmlElement)GetPage(DocumentId);
var x = (XmlElement)GetPage(DocumentId);
if (x == null)
throw new Exception("Document is not protected!");
else
using (new WriteLock(Locker))
{
if (x.SelectSingleNode("group [@id = '" + MemberGroupId.ToString() + "']") == null)
if (x.SelectSingleNode("group [@id = '" + MemberGroupId + "']") == null)
{
XmlElement groupXml = (XmlElement)AccessXml.CreateNode(XmlNodeType.Element, "group", "");
groupXml.SetAttribute("id", MemberGroupId.ToString());
var groupXml = (XmlElement)x.OwnerDocument.CreateNode(XmlNodeType.Element, "group", "");
groupXml.SetAttribute("id", MemberGroupId.ToString(CultureInfo.InvariantCulture));
x.AppendChild(groupXml);
Save();
Save(x.OwnerDocument);
}
}
}
@@ -117,122 +162,130 @@ namespace umbraco.cms.businesslogic.web
[Obsolete("This method is no longer supported. Use the ASP.NET MemberShip methods instead", true)]
public static void AddMemberToDocument(int DocumentId, int MemberId)
{
XmlElement x = (XmlElement)GetPage(DocumentId);
var x = (XmlElement)GetPage(DocumentId);
if (x == null)
throw new Exception("Document is not protected!");
else
using (new WriteLock(Locker))
{
if (x.Attributes.GetNamedItem("memberId") != null)
x.Attributes.GetNamedItem("memberId").Value = MemberId.ToString();
{
x.Attributes.GetNamedItem("memberId").Value = MemberId.ToString(CultureInfo.InvariantCulture);
}
else
x.SetAttribute("memberId", MemberId.ToString());
Save();
{
x.SetAttribute("memberId", MemberId.ToString(CultureInfo.InvariantCulture));
}
Save(x.OwnerDocument);
}
}
public static void AddMembershipUserToDocument(int documentId, string membershipUserName)
{
//event
AddMembershipUserToDocumentEventArgs e = new AddMembershipUserToDocumentEventArgs();
var e = new AddMembershipUserToDocumentEventArgs();
new Access().FireBeforeAddMembershipUserToDocument(new Document(documentId), membershipUserName, e);
if (!e.Cancel)
if (e.Cancel) return;
using (new WriteLock(Locker))
{
XmlElement x = (XmlElement)GetPage(documentId);
var x = (XmlElement)GetPage(documentId);
if (x == null)
throw new Exception("Document is not protected!");
else
{
if (x.Attributes.GetNamedItem("memberId") != null)
x.Attributes.GetNamedItem("memberId").Value = membershipUserName;
else
x.SetAttribute("memberId", membershipUserName);
Save();
}
new Access().FireAfterAddMembershipUserToDocument(new Document(documentId), membershipUserName, e);
if (x.Attributes.GetNamedItem("memberId") != null)
x.Attributes.GetNamedItem("memberId").Value = membershipUserName;
else
x.SetAttribute("memberId", membershipUserName);
Save(x.OwnerDocument);
}
new Access().FireAfterAddMembershipUserToDocument(new Document(documentId), membershipUserName, e);
}
[Obsolete("This method is no longer supported. Use the ASP.NET MemberShip methods instead", true)]
public static void RemoveMemberGroupFromDocument(int DocumentId, int MemberGroupId)
{
XmlElement x = (XmlElement)GetPage(DocumentId);
if (x == null)
throw new Exception("Document is not protected!");
else
using (new WriteLock(Locker))
{
XmlNode xGroup = x.SelectSingleNode("group [@id = '" + MemberGroupId.ToString() + "']");
if (xGroup != null)
{
x.RemoveChild(xGroup);
Save();
}
var x = (XmlElement)GetPage(DocumentId);
if (x == null)
throw new Exception("Document is not protected!");
var xGroup = x.SelectSingleNode("group [@id = '" + MemberGroupId + "']");
if (xGroup == null) return;
x.RemoveChild(xGroup);
Save(x.OwnerDocument);
}
}
public static void RemoveMembershipRoleFromDocument(int documentId, string role)
{
RemoveMemberShipRoleFromDocumentEventArgs e = new RemoveMemberShipRoleFromDocumentEventArgs();
var e = new RemoveMemberShipRoleFromDocumentEventArgs();
new Access().FireBeforeRemoveMemberShipRoleFromDocument(new Document(documentId), role, e);
if (!e.Cancel)
{
XmlElement x = (XmlElement)GetPage(documentId);
if (e.Cancel) return;
using (new WriteLock(Locker))
{
var x = (XmlElement)GetPage(documentId);
if (x == null)
throw new Exception("Document is not protected!");
else
{
XmlNode xGroup = x.SelectSingleNode("group [@id = '" + role + "']");
if (xGroup != null)
{
x.RemoveChild(xGroup);
Save();
}
}
var xGroup = x.SelectSingleNode("group [@id = '" + role + "']");
new Access().FireAfterRemoveMemberShipRoleFromDocument(new Document(documentId), role, e);
if (xGroup != null)
{
x.RemoveChild(xGroup);
Save(x.OwnerDocument);
}
}
new Access().FireAfterRemoveMemberShipRoleFromDocument(new Document(documentId), role, e);
}
public static bool RenameMemberShipRole(string oldRolename, string newRolename)
{
bool hasChange = false;
if (oldRolename != newRolename)
var hasChange = false;
if (oldRolename == newRolename) return false;
using (new WriteLock(Locker))
{
var xDoc = GetXmlDocumentCopy();
oldRolename = oldRolename.Replace("'", "&apos;");
foreach (XmlNode x in AccessXml.SelectNodes("//group [@id = '" + oldRolename + "']"))
foreach (XmlNode x in xDoc.SelectNodes("//group [@id = '" + oldRolename + "']"))
{
x.Attributes["id"].Value = newRolename;
hasChange = true;
}
if (hasChange)
Save();
Save(xDoc);
}
return hasChange;
}
public static void ProtectPage(bool Simple, int DocumentId, int LoginDocumentId, int ErrorDocumentId)
{
AddProtectionEventArgs e = new AddProtectionEventArgs();
var e = new AddProtectionEventArgs();
new Access().FireBeforeAddProtection(new Document(DocumentId), e);
if (!e.Cancel)
{
if (e.Cancel) return;
using (new WriteLock(Locker))
{
var x = (XmlElement)GetPage(DocumentId);
XmlElement x = (XmlElement)GetPage(DocumentId);
if (x == null)
{
x = (XmlElement)_accessXmlContent.CreateNode(XmlNodeType.Element, "page", "");
AccessXml.DocumentElement.AppendChild(x);
var xDoc = GetXmlDocumentCopy();
x = (XmlElement)xDoc.CreateNode(XmlNodeType.Element, "page", "");
x.OwnerDocument.DocumentElement.AppendChild(x);
}
// if using simple mode, make sure that all existing groups are removed
else if (Simple)
@@ -243,67 +296,53 @@ namespace umbraco.cms.businesslogic.web
x.SetAttribute("loginPage", LoginDocumentId.ToString());
x.SetAttribute("noRightsPage", ErrorDocumentId.ToString());
x.SetAttribute("simple", Simple.ToString());
Save();
Save(x.OwnerDocument);
ClearCheckPages();
new Access().FireAfterAddProtection(new Document(DocumentId), e);
}
new Access().FireAfterAddProtection(new Document(DocumentId), e);
}
public static void RemoveProtection(int DocumentId)
{
XmlElement x = (XmlElement)GetPage(DocumentId);
if (x != null)
//event
var e = new RemoveProtectionEventArgs();
new Access().FireBeforeRemoveProtection(new Document(DocumentId), e);
if (e.Cancel) return;
using (new WriteLock(Locker))
{
//event
RemoveProtectionEventArgs e = new RemoveProtectionEventArgs();
new Access().FireBeforeRemoveProtection(new Document(DocumentId), e);
if (!e.Cancel)
{
x.ParentNode.RemoveChild(x);
Save();
ClearCheckPages();
new Access().FireAfterRemoveProtection(new Document(DocumentId), e);
}
var x = (XmlElement)GetPage(DocumentId);
if (x == null) return;
x.ParentNode.RemoveChild(x);
Save(x.OwnerDocument);
ClearCheckPages();
}
}
private static void Save()
{
SaveEventArgs e = new SaveEventArgs();
new Access().FireAfterRemoveProtection(new Document(DocumentId), e);
}
#endregion
new Access().FireBeforeSave(e);
if (!e.Cancel)
{
System.IO.FileStream f = System.IO.File.Open(_accessXmlSource, FileMode.Create);
AccessXml.Save(f);
f.Close();
new Access().FireAfterSave(e);
}
}
#region Reading methods
[Obsolete("This method is no longer supported. Use the ASP.NET MemberShip methods instead", true)]
public static bool IsProtectedByGroup(int DocumentId, int GroupId)
{
bool isProtected = false;
cms.businesslogic.web.Document d = new Document(DocumentId);
var d = new Document(DocumentId);
if (!IsProtected(DocumentId, d.Path))
isProtected = false;
else
using (new ReadLock(Locker))
{
XmlNode currentNode = GetPage(GetProtectedPage(d.Path));
if (currentNode.SelectSingleNode("./group [@id=" + GroupId.ToString() + "]") != null)
if (IsProtectedInternal(DocumentId, d.Path))
{
isProtected = true;
var currentNode = GetPage(GetProtectedPage(d.Path));
if (currentNode.SelectSingleNode("./group [@id=" + GroupId + "]") != null)
{
isProtected = true;
}
}
}
@@ -314,16 +353,17 @@ namespace umbraco.cms.businesslogic.web
{
bool isProtected = false;
CMSNode d = new CMSNode(documentId);
var d = new CMSNode(documentId);
if (!IsProtected(documentId, d.Path))
isProtected = false;
else
using (new ReadLock(Locker))
{
XmlNode currentNode = GetPage(GetProtectedPage(d.Path));
if (currentNode.SelectSingleNode("./group [@id='" + role + "']") != null)
if (IsProtectedInternal(documentId, d.Path))
{
isProtected = true;
var currentNode = GetPage(GetProtectedPage(d.Path));
if (currentNode.SelectSingleNode("./group [@id='" + role + "']") != null)
{
isProtected = true;
}
}
}
@@ -332,32 +372,34 @@ namespace umbraco.cms.businesslogic.web
public static string[] GetAccessingMembershipRoles(int documentId, string path)
{
ArrayList roles = new ArrayList();
var roles = new ArrayList();
if (!IsProtected(documentId, path))
return null;
else
using (new ReadLock(Locker))
{
XmlNode currentNode = GetPage(GetProtectedPage(path));
if (IsProtectedInternal(documentId, path) == false)
return null;
var currentNode = GetPage(GetProtectedPage(path));
foreach (XmlNode n in currentNode.SelectNodes("./group"))
{
roles.Add(n.Attributes.GetNamedItem("id").Value);
}
return (string[])roles.ToArray(typeof(string));
}
return (string[])roles.ToArray(typeof(string));
}
[Obsolete("This method is no longer supported. Use the ASP.NET MemberShip methods instead", true)]
public static cms.businesslogic.member.MemberGroup[] GetAccessingGroups(int DocumentId)
public static member.MemberGroup[] GetAccessingGroups(int DocumentId)
{
cms.businesslogic.web.Document d = new Document(DocumentId);
var d = new Document(DocumentId);
if (!IsProtected(DocumentId, d.Path))
return null;
else
using (new ReadLock(Locker))
{
XmlNode currentNode = GetPage(GetProtectedPage(d.Path));
if (IsProtectedInternal(DocumentId, d.Path) == false)
return null;
var currentNode = GetPage(GetProtectedPage(d.Path));
var mg = new member.MemberGroup[currentNode.SelectNodes("./group").Count];
int count = 0;
foreach (XmlNode n in currentNode.SelectNodes("./group"))
@@ -371,76 +413,79 @@ namespace umbraco.cms.businesslogic.web
}
[Obsolete("This method is no longer supported. Use the ASP.NET MemberShip methods instead", true)]
public static cms.businesslogic.member.Member GetAccessingMember(int DocumentId)
public static member.Member GetAccessingMember(int DocumentId)
{
cms.businesslogic.web.Document d = new Document(DocumentId);
var d = new Document(DocumentId);
if (!IsProtected(DocumentId, d.Path))
return null;
else if (GetProtectionType(DocumentId) != ProtectionType.Simple)
throw new Exception("Document isn't protected using Simple mechanism. Use GetAccessingMemberGroups instead");
else
using (new ReadLock(Locker))
{
XmlNode currentNode = GetPage(GetProtectedPage(d.Path));
if (currentNode.Attributes.GetNamedItem("memberId") != null)
return new cms.businesslogic.member.Member(int.Parse(
currentNode.Attributes.GetNamedItem("memberId").Value));
else
throw new Exception("Document doesn't contain a memberId. This might be caused if document is protected using umbraco RC1 or older.");
if (IsProtectedInternal(DocumentId, d.Path) == false)
return null;
if (GetProtectionTypeInternal(DocumentId) != ProtectionType.Simple)
throw new Exception("Document isn't protected using Simple mechanism. Use GetAccessingMemberGroups instead");
var currentNode = GetPage(GetProtectedPage(d.Path));
if (currentNode.Attributes.GetNamedItem("memberId") != null)
return new member.Member(int.Parse(
currentNode.Attributes.GetNamedItem("memberId").Value));
}
throw new Exception("Document doesn't contain a memberId. This might be caused if document is protected using umbraco RC1 or older.");
}
public static MembershipUser GetAccessingMembershipUser(int documentId)
{
CMSNode d = new CMSNode(documentId);
var d = new CMSNode(documentId);
if (!IsProtected(documentId, d.Path))
return null;
else if (GetProtectionType(documentId) != ProtectionType.Simple)
throw new Exception("Document isn't protected using Simple mechanism. Use GetAccessingMemberGroups instead");
else
using (new ReadLock(Locker))
{
XmlNode currentNode = GetPage(GetProtectedPage(d.Path));
if (IsProtectedInternal(documentId, d.Path) == false)
return null;
if (GetProtectionTypeInternal(documentId) != ProtectionType.Simple)
throw new Exception("Document isn't protected using Simple mechanism. Use GetAccessingMemberGroups instead");
var currentNode = GetPage(GetProtectedPage(d.Path));
if (currentNode.Attributes.GetNamedItem("memberId") != null)
{
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
return provider.GetUser(currentNode.Attributes.GetNamedItem("memberId").Value, true);
}
else
{
throw new Exception("Document doesn't contain a memberId. This might be caused if document is protected using umbraco RC1 or older.");
}
}
throw new Exception("Document doesn't contain a memberId. This might be caused if document is protected using umbraco RC1 or older.");
}
[Obsolete("This method is no longer supported. Use the ASP.NET MemberShip methods instead", true)]
public static bool HasAccess(int DocumentId, cms.businesslogic.member.Member Member)
public static bool HasAccess(int DocumentId, member.Member Member)
{
bool hasAccess = false;
cms.businesslogic.web.Document d = new Document(DocumentId);
var d = new Document(DocumentId);
if (!IsProtected(DocumentId, d.Path))
hasAccess = true;
else
using (new ReadLock(Locker))
{
XmlNode currentNode = GetPage(GetProtectedPage(d.Path));
if (Member != null)
if (IsProtectedInternal(DocumentId, d.Path) == false)
{
IDictionaryEnumerator ide = Member.Groups.GetEnumerator();
while (ide.MoveNext())
hasAccess = true;
}
else
{
var currentNode = GetPage(GetProtectedPage(d.Path));
if (Member != null)
{
cms.businesslogic.member.MemberGroup mg = (cms.businesslogic.member.MemberGroup)ide.Value;
if (currentNode.SelectSingleNode("./group [@id=" + mg.Id.ToString() + "]") != null)
var ide = Member.Groups.GetEnumerator();
while (ide.MoveNext())
{
hasAccess = true;
break;
var mg = (member.MemberGroup)ide.Value;
if (currentNode.SelectSingleNode("./group [@id=" + mg.Id.ToString() + "]") != null)
{
hasAccess = true;
break;
}
}
}
}
@@ -454,41 +499,19 @@ namespace umbraco.cms.businesslogic.web
bool hasAccess = false;
var node = new CMSNode(documentId);
if (IsProtected(documentId, node.Path) == false)
return true;
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
var member = provider.GetUser(memberId, true);
var currentNode = GetPage(GetProtectedPage(node.Path));
if (member != null)
using (new ReadLock(Locker))
{
foreach (string role in Roles.GetRolesForUser())
{
if (currentNode.SelectSingleNode("./group [@id='" + role + "']") != null)
{
hasAccess = true;
break;
}
}
}
return hasAccess;
}
if (IsProtectedInternal(documentId, node.Path) == false)
return true;
public static bool HasAccess(int documentId, string path, MembershipUser member)
{
bool hasAccess = false;
var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
var member = provider.GetUser(memberId, true);
var currentNode = GetPage(GetProtectedPage(node.Path));
if (!IsProtected(documentId, path))
hasAccess = true;
else
{
XmlNode currentNode = GetPage(GetProtectedPage(path));
if (member != null)
{
string[] roles = Roles.GetRolesForUser(member.UserName);
foreach (string role in roles)
foreach (string role in Roles.GetRolesForUser())
{
if (currentNode.SelectSingleNode("./group [@id='" + role + "']") != null)
{
@@ -502,28 +525,105 @@ namespace umbraco.cms.businesslogic.web
return hasAccess;
}
public static bool HasAccess(int documentId, string path, MembershipUser member)
{
bool hasAccess = false;
using (new ReadLock(Locker))
{
if (IsProtectedInternal(documentId, path) == false)
{
hasAccess = true;
}
else
{
XmlNode currentNode = GetPage(GetProtectedPage(path));
if (member != null)
{
string[] roles = Roles.GetRolesForUser(member.UserName);
foreach (string role in roles)
{
if (currentNode.SelectSingleNode("./group [@id='" + role + "']") != null)
{
hasAccess = true;
break;
}
}
}
}
}
return hasAccess;
}
public static ProtectionType GetProtectionType(int DocumentId)
{
XmlNode x = GetPage(DocumentId);
try
using (new ReadLock(Locker))
{
if (bool.Parse(x.Attributes.GetNamedItem("simple").Value))
return ProtectionType.Simple;
else
return ProtectionType.Advanced;
}
catch
{
return ProtectionType.NotProtected;
XmlNode x = GetPage(DocumentId);
try
{
return bool.Parse(x.Attributes.GetNamedItem("simple").Value)
? ProtectionType.Simple
: ProtectionType.Advanced;
}
catch
{
return ProtectionType.NotProtected;
}
}
}
public static bool IsProtected(int DocumentId, string Path)
{
using (new ReadLock(Locker))
{
return IsProtectedInternal(DocumentId, Path);
}
}
public static int GetErrorPage(string Path)
{
using (new ReadLock(Locker))
{
return int.Parse(GetPage(GetProtectedPage(Path)).Attributes.GetNamedItem("noRightsPage").Value);
}
}
public static int GetLoginPage(string Path)
{
using (new ReadLock(Locker))
{
return int.Parse(GetPage(GetProtectedPage(Path)).Attributes.GetNamedItem("loginPage").Value);
}
}
#endregion
private static ProtectionType GetProtectionTypeInternal(int DocumentId)
{
//NOTE: No locks here! the locking is done in callers to this method
XmlNode x = GetPage(DocumentId);
try
{
return bool.Parse(x.Attributes.GetNamedItem("simple").Value)
? ProtectionType.Simple
: ProtectionType.Advanced;
}
catch
{
return ProtectionType.NotProtected;
}
}
private static bool IsProtectedInternal(int DocumentId, string Path)
{
//NOTE: No locks here! the locking is done in callers to this method
bool isProtected = false;
if (!CheckedPages.ContainsKey(DocumentId))
if (CheckedPages.ContainsKey(DocumentId) == false)
{
foreach (string id in Path.Split(','))
{
@@ -534,32 +634,44 @@ namespace umbraco.cms.businesslogic.web
}
}
// Add thread safe updating to the hashtable
if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Application.Lock();
if (!CheckedPages.ContainsKey(DocumentId))
if (CheckedPages.ContainsKey(DocumentId) == false)
{
CheckedPages.Add(DocumentId, isProtected);
if (System.Web.HttpContext.Current != null)
System.Web.HttpContext.Current.Application.UnLock();
}
}
else
{
isProtected = (bool)CheckedPages[DocumentId];
}
return isProtected;
}
public static int GetErrorPage(string Path)
private static void Save(XmlDocument newDoc)
{
return int.Parse(GetPage(GetProtectedPage(Path)).Attributes.GetNamedItem("noRightsPage").Value);
}
//NOTE: No locks here! the locking is done in callers to this method
public static int GetLoginPage(string Path)
{
return int.Parse(GetPage(GetProtectedPage(Path)).Attributes.GetNamedItem("loginPage").Value);
var e = new SaveEventArgs();
new Access().FireBeforeSave(e);
if (e.Cancel) return;
using (var f = File.Open(_accessXmlFilePath, FileMode.Create))
{
newDoc.Save(f);
f.Close();
//set the underlying in-mem object to null so it gets re-read
_accessXmlContent = null;
}
new Access().FireAfterSave(e);
}
private static int GetProtectedPage(string Path)
{
//NOTE: No locks here! the locking is done in callers to this method
int protectedPage = 0;
foreach (string id in Path.Split(','))
@@ -571,10 +683,17 @@ namespace umbraco.cms.businesslogic.web
private static XmlNode GetPage(int documentId)
{
XmlNode x = AccessXml.SelectSingleNode("/access/page [@id=" + documentId.ToString() + "]");
//NOTE: No locks here! the locking is done in callers to this method
var xDoc = GetXmlDocumentCopy();
var x = xDoc.SelectSingleNode("/access/page [@id=" + documentId + "]");
return x;
}
private static void ClearCheckPages()
{
CheckedPages.Clear();
}
//Event delegates
public delegate void SaveEventHandler(Access sender, SaveEventArgs e);