In Sitecore how to determine if a role was explicitly denied read access to an item?

272 Views Asked by At

I have a solution built with Sitecore 7.5 and Solr 4.7. We have a need to restrict a search of documents from the Media Library so that it only returns the documents that the current logged in user (or anonymous user) has access to. Our current solution involves adding a list of Denied Roles and Read Roles to custom fields in the index. Then at query time we can construct a query that only returns items from the index where the user belongs to at least one of the roles in the Read Roles list and does not belong to any of the roles in the Denied Roles list.

The problem (I believe) that we are having is how the list of Denied Roles gets created. Here is the code that we are using in the custom Solr field.

public class DenyReadItemRoles : PermissionsRoleBase {
    protected override object GetPermissibles(ItemSecurity security) {
        List<string> rolesList = null;
        using (new Sitecore.SecurityModel.SecurityEnabler()) {
            var roles = RolesInRolesManager.GetAllRoles();
            var denyRoles = roles.Where(r => !security.CanRead(r));

            if (denyRoles != null && denyRoles.Any()) {
                rolesList = denyRoles.Select(r => r.Name).ToList();
            }
        }
        return rolesList;
    }
}

This code uses the CanRead() method to determine if a particular role has access to an item. This is the role's effective read rights. However, sometimes a role may have been explicitly denied read access to an item and sometimes it may have just had inheritance removed and may simply not have any rights to the item. This is a subtle difference. In Sitecore if a role has been explicitly denied access to an item then that should override everything else. In these cases our current code works fine. But other times in Sitecore you may have just broken inheritance and removed all permissions for a given folder or item. In this case the role doesn't have read access to the item but it was not explicit. So in this case if the user belongs to a different role that does have access to the item, then the user should have access to the item. This is where our code is failing.

So the question I am asking is this - is there some other way in my custom Solr field that I can tell the difference between a role that simply doesn't have read access and a role that was explicitly denied read access to an item?

1

There are 1 best solutions below

0
maz On

I think you may be forced to go up the tree in your indexing code, to filter out non-explicit denials. A naive implementation might look something like this (untested) code:

public class ExplicitlyDenyReadItemRoles : PermissionsRoleBase {
    protected override object GetPermissibles(Item item) {
        List<string> rolesList = null;
        using (new Sitecore.SecurityModel.SecurityEnabler()) {
            var roles = RolesInRolesManager.GetAllRoles();
            var denyRoles = roles.Where(r => r.IsDenied(item));

            if (denyRoles != null && denyRoles.Any()) {
                rolesList = denyRoles.Select(r => r.Name).ToList();
            }
        }
        return rolesList;
    }
}

internal static class SecurityExtensions {
    internal static bool IsDenied(this Role role, Item item) {
        if (item.Security.CanRead(role)) return false;
        AccessRuleCollection accessRules = item.Security.GetAccessRules();
        if (accessRules != null) {
            foreach (AccessRule rule in accessRules) {
                if (rule.SecurityPermission == SecurityPermission.DenyAccess
                    && rule.AccessRight == AccessRight.ItemRead
                    && rule.Account == role
                    && rule.PropagationType != PropagationType.Entity) {
                    return true;
                }
            }
        }
        return (item.Parent == null) ? false : role.IsDenied(item.Parent);
    }
}

Not exactly great for indexing performance. Note that I had to change from ItemSecurity to Item, in order to walk "up the tree".

An alternative which has been suggested here and elsewhere is to filter out the results after indexing. But of course, this is not ideal for performance when paging results.

Closely related to: Indexing Sitecore Item security and restricting returned search results