I'm currently working on a SharePoint project that makes extensive use of programmatically setting ListItem ACL's. There is a List Event Handler which sets ACLs on the ItemAdded event, but then there is an administrative interface that enables administrators to reassign list items to another user which effectively means replacing the ACLs for the ListItem to give another user Contribute.
In any event, I keep encountering the dreadful "The security validation for this page is invalid" error when trying to perform the ACL updates, specifically from web parts (haven't seemed to have this issue on list event handlers). Well it appears that I've finally come up with the magic combination of fixes. There are several blog postings out there indicating that you should use "AllowUnsafeUpdates" on your SPWeb object. This seems to fix things for many people, however, the code I was working on calls "BreakRoleInheritance". Apparently that bugger ends up reverting the "AllowUnsafeUpdates" flag back to false after you call it!
Here's the information that Paul Yau shared in a thread on the MSDN forums which took care of my issue, thanks for sharing Paul!
When you call SPList.BreakRoleInheritance(false) from an HTTP GET request, although you have specified SPWeb.AllUnsafeUpdates=true, you will still be thrown an exception
Updates are currently disallowed on GET requests. To allow updates on a GET, set the 'AllowUnsafeUpdates' property on SPWeb.
This is by design limitation of SPList.BreakRoleInheritance
BreakRoleInheritance does it work in two steps. First, it needs to revert its permission to have same permission settings as parent (this is a less expensive operation, and give the list a fresh start on its road to unique permission). Later it checks CopyRoleAssignments parameter. If it is false, it takes an extra step to clean up permission on the list. A side effect of step 1 is that it dirties some internal objects in SPWeb, and cause them to be recreated. Unfortunately, the re-creation of those internal objects cause SPWeb.AllowUnsafeUpdates to have a default value which is false. That is, SPWeb.AllowUnsafeUpdates is reset in middle of call to SPList.BreakRoleInheritance, therefore we got the exception.
There are two possible workarounds to the issue:
1. Call SPList.BreakRoleInheritance from a HTTP POST request. That is, we can first have a button on UI and have users to click. In response to users’ click, we call SPList.BreakRoleInheritance. There is a first HTTP GET request by which, SharePoint has a chance to embed some digest to validate requests on return (HTTP POST). Therefore, we no longer need to set SPWeb.AllowUnsafeUpdates=true. This is recommended approach from security perspective.
2. First call SPList.BreakRoleInheritance(true). Then, use custom code to clean up permission and create your own permission set for the list as needed. The sample code are:
SPWeb web = SPControl.GetContextWeb(this.Context);
SPListCollection lists = web.Lists;
//Guid docLibGuid = lists.Add("Doc Lib Sample 1", "Doc Lib Desc", SPListTemplateType.DocumentLibrary);
//SPList docLib = lists[docLibGuid];
SPList docLib = lists["Doc Lib Sample 1"];
//docLib.ParentWeb.AllowUnsafeUpdates = true;
docLib.BreakRoleInheritance(true); //Exception throw here when the parameters is "false"
web.AllowUnsafeUpdates = true;
SPRoleAssignmentCollection roleAssigns = docLib.RoleAssignments;
for (int i = roleAssigns.Count-1; i >= 0; i--)