Or as I like to call it - Fun with PrincipalObjectAccess records!
Consider the following scenario.
- My organisation has the Parent Account (account_parent_account) relationship set up with the following:
- 'Cascade Share' behaviour set to 'Cascade User-owned'.
- 'Cascade UnShare' behaviour set to 'Cascade User-owned'.
- User1 creates an account and names it "Test Parent".
- User1 then creates a child account to the previous named "Test Child".
- User1 shares "Test Parent" to User2 with the 'read' permission. This causes the system to create an inherited share for "Test Child" for User2.
- User3 takes ownership of "Test Child".
- User1 now revokes sharing on "Test Parent" from User2.
- Result - User2 is left with 'read' permissions to "Test Child" which no one has any way of removing or even seeing as inherited permissions are not visible in the CRM UI.
Test it, works every time.
Going to a more technical view, the PrincipalObjectAccess table is designed to store both directly granted permissions (AccessRightsMask) and indirectly granted permissions (InheritedAccessRightsMask). These will generally come in pairs or chains where one or more inherited permissions have a directly granted permission at the top.
What happens in the sequence described above is that we are left with inherited permissions to records that are not linked to directly granted permissions. As a result they cannot be removed and are just left as orphaned permissions floating in the system.
Back to my real-life CRM system. It now appears that I have thousands (if not more) of these ghost permissions floating around as I have no easy or supported way of removing them. Some users have access to data they are not supposed to see.
Any ideas?
You know you want to, it's a challenging problem! ;)
To keep this post short, I have not provided any queries or heavy technical details. I will provide those in another post.