Assume you have a SharePoint site / list, and you would like to know if it has any content configured with unique permissions, that means any content (list / folder / list item) that does not inherit the permissions configured for the current site / list. It is easy to see this information from the user interface, when you check the permissions configured for the given site / list object through the page _layouts/user.aspx.
But how could we get the same information if we need to access it from code? One logical solution would be to iterate through all subsites / lists / folders / items, and see if any of them has its HasUniqueRoleAssignments property (inherited from the SPSecurableObject base class that implements the obsolete ISecurableObject interface) with value true. Although this approach should definitely do the job, it might be not the most effective and simplest solution. Let’s see instead, how it is implemented in the UserRoles class (namespace and assembly Microsoft.SharePoint.ApplicationPages) that is the class behind the user.aspx page.
The base class of the UserRoles is the CBaseAclPage class, that has a public field called m_Securable of type SPSecurableObject. This field contains the related SPWeb / SPList / SPItem object, all of these are derived classes of the SPSecurableObject class. The highlighted message on the above screenshot comes from the SetExceptionStatus() method (declared as private) of the UserRoles class. In this method we check first if we have an SPWeb or an SPList in the m_Securable field.
If the m_Securable is an SPWeb, we call its internal HasListsWithUniquePermissions() method. If the m_Securable is an SPList, we check its internal HasUniqueScopes property. As the objects of type SPItem (the third derived type of SPSecurableObject) may not have any child objects, it has no sense to check for content with unique permissions in this case.
Note: Well, I did not tell the truth in my previous sentence. We might have folders (also SPItem objects, see Folder property of the SPListItem, inherited from SPItem) in our lists, that contain items with unique permissions. In this case this fact should be indicated on the UI, but I found, that the user.aspx page / UserRoles class ignores this fact. We do as well in this post, and restrict our scope to sites and lists.
Note 2: I’ve found that the Permissions page simply ignores subsites with unique permission. Should you have a site with a subsite, and the subsite configured with its own permission set, the Permissions page of the parent site does not indicate this. This seems to be a bug, but we follow this buggy behavior in this post. Instead of this, we could call the public GetWebsAndListsWithUniquePermissions() method of SPWeb and check the count of items returned by the method. If the count is greater than one, the site has content with unique permissions. This approach works, even if not the subsite itself, but one of its list has unique permissions. But wait a minute! A new problem arose… This method returns subsites / lists that had formerly unique permissions, but later this unique permission set was removed by inheriting back the parent permissions. What to do now? The GetWebsAndListsWithUniquePermissions() method returns a collection of SPWebListInfo objects, and this type has a property called HasUniqueRoleAssignments. It means, a viable alternative of the buggy out-of-the-box solution might be:
bool hasUniquePerms = web.GetWebsAndListsWithUniquePermissions().Any(p => p.HasUniqueRoleAssignments);
But back to the original behavior… It’s quite easy to implement the same logic in our own code by accessing the above mentioned members via reflection.
I’ve created a few extension methods to achieve this goal:
Having this methods you can call the HasSubItemWithUniquePermissions method on your SPWeb / SPList instances (or even in case of SPItem as well, although in this case you will always receive a value of false), and check, if these object have any content with unique permissions.
Note: In my case I declared the helper methods as internal. However, if you wish to access the functionality from external assemblies as well, you might want to declare the HasSubItemWithUniquePermissions method (and the Extensions class itself) as public.
I will demonstrate the usage of these methods in a sample application in an upcoming post (see here).