There are many good resources to understand how Salesforce permissions are granted, but not as many detailing out what’s happening “under the hood” when, say, a field permission is added.
So as I seem to have gone and gained a fair bit of information on them and I like sharing my knowledge, as one former colleague of mine put it: Bits like when they’re moved - I figured I might write something about them.
Edited to add: 6th part, will be about file & document sharing.
Intro
But the topic is vast. Salesforce has documented and published documentation for almost everything, and still it’s taken me years of learning, mostly by doing (mistakes 😋), to get to where I am - and with some of things I’ll be discussing, I’m going fairly deep, so in order to avoid everyone’s eyes being glazed over and brains zoned out & mushy after the first few bits, I’ll be doing this in bits & pieces, i.e. a series of articles instead of One Big Article.
I have done a bit of thinking on how to organize this, and here’s a rough outline of how I’m thinking about this now; it may change, depending on what I come across while writing and so on.
Part 1
This intro
Objects
Object properties
Object permissions
Field permissions
Table structure
Fun things
Part 2
Profiles
Permission Sets
Permission Set Groups
Permission Set (group) Assignments
Fun things
Part 3
Default sharing
Sharing Rules
Custom Sharing Reasons
Manual Sharing
Implicit Sharing
Fun things
Part 4
Role hierarchy
Groups
Role Groups
Account / Case / Opportunity Teams
Fun things
Part 5
External Sharing
External Role Hierarchy
Sharing Sets
Sharing Groups
Fun things
Part 6
File Sharing
Document Sharing
Libraries
External sharing
If you happen to have requests, wishes or such, or if something I’ve shared doesn’t make sense or you feel like it is incorrect, feel free to ping me, comment here and so on.
Objects
Well, here we are. Objects are a fairly fundamental level of a creature in Salesforce, and many of us feel like we know what they are and how they work… including me.
Thing is, though, that nearly every time I feel like I’ve got a hang of something in Salesforce, there’s the inevitable ye olde TV Shoppe moment with the obligatory “But Wait - There’s More!”.
Including very basic things like object permissions and properties.
The most common analogy I’ve heard used (and often in trainings used myself) with objects is the old Excel sheet, where the sheet is the object, columns are fields and rows with their data entered into those columns form up records within that object - the which is a good analogy, but it is not quite complete; thing is, that objects have non-field properties as well, such as name, label and so on.
Now, for good and ill, Salesforce is a database. Or a database application, if you prefer; regardless, one of the implications of that is also objects and their properties are stored in a table in the database.
Side story: Few years back I shared that with my son who really likes dad jokes and of course he found it quite funny. Now, few weeks later I’m working in the living room, he comes and says that he has a joke for me - predictably, it’s a dad joke, we laugh at it…
…and when he heads back to his room, he very, very casually throws over his shoulder “you can store it in the dad-a-base”. I think he’d been planning it for days. At least.
Anyway, the Table Of Objects isn’t Objects - it’s called EntityDefinitions. Of course, this table stores all kinds of entities, not just objects.
One of the curiosities of that table is that unlike most tables in Salesforce, the ID of every record in that table is “000000000000000AAA”; therefore you can’t use that as an identifier, so when searching the entity definition we want, we’ll need rely on other fields, like Label and perhaps more reliably, DeveloperName.
This isn’t a big issue, if you don’t want to manipulate either records in that table or else records that relate to records in that table - say, for example, permissions.
With Label and DeveloperName values we should bear in mind that these are not mutually interchangeable, nor always the same in all situations. For example, in most cases and orgs the Label Contact will correspond with the DeveloperName value Contact, but e.g. in Energy and Utilities Cloud, the Label corresponding to DeveloperName Contact will be Person.
…and while when we’re configuring things, as most of us know, all custom items’ “API name” value will end with __c, __mdt or __e, depending or their type - but if you run a query in the EntityDefinitions table, you’ll note that to find out the type, you’ll need to include the field QualifiedApiName field too:
Of these four objects, I’ve created the last three; I just was too energy efficient to start filtering out the Customer entity definition, but it dovetails here nicely, because from the missing __xyz you’ll see that it’s a standard entity type.
Now - if you want the full details of entity definitions, you can read more about them here, in the official Salesforce Tooling API documentation.
One of the nice fields in there is the IsTriggerable boolean; not one, but two times in the past, when knowing that was there and could have been queried would have saved me several hours of debug work… but I digress.
Okay, this covers some of the object things, but how do these relate to permissions?
Object Permissions
Now - to answer that question, we’ll need to look into another specific entity type - ObjectPermissions. And yes, it’s an entity type, just as the object itself, and somewhat predictably, we can query it, like so:
These are Object Permissions for Account object in a very nearly out of the box Trailhead org, and I added the basic object permissions there.
Now that could be easily modified, say to look up which Object Permissions hand out, say, Modify All Records permission; I added a few more fields to the query to display the parent ID and name:
Now - you’ll see in the Parent column that all parents of the ObjectPermissions records are Permission Sets, and you’ll be “Hang on, what about Profiles?”
Well, those X00-starting permission sets are actually something called Profile Permission Sets, from which we can deduce that while the profiles still exist, and you can still grant permissions through them, the underlying mechanism of permission granting for both profiles and permission sets is the same. I’ll do a deeper dive on that topic later, probably in the next part of the series.
Anywho - here’s a link to Salesforce’s API documentation for Object Permissions.
Field Permissions
…and this would be yet another Entity, found by name FieldPermissions.
While Object Permissions define object level access (CRED + W/A + M/A), Field Permissions define read / write or muting of read / write permissions for individual fields, if they’re attached to a muting permission set, another thing I’ll walk you through in Part 2.
Here I queried field permissions for Account object in the same org as before:
Note that all field permission shown here - a small subset of all of the Account’s field permissions - relate to the same parent permission set, which is again a profile permission set.
Here’s again a link to the Salesforce official API documentation for the Field Permissions object.
Table Structure
Now, once we look at it as a bit larger picture, it gets pretty straightforward; we have Object Permissions, Field Permissions, Permission Sets and Objects themselves in a structure that looks something like this:
The object “box” is separate here on purpose, as it’s sort of related, in terms of that while the three other entities do define metadata for the object, but there is no direct relation from any of the other three entities to it.
The field permissions and object permissions are children (details, really) of permission sets, and none of them are linked to the object entity itself; if we look at one of the field permissions for Account, Active__c, we’ll see that the relation to Account is not a lookup, but a picklist field:
Nothing wrong with picklists - they seem to be getting the job done.
Fun Things
Well, I did promise, so… although how fun you find this may vary a bit on your sense of humor, but I do find most things that spare me work and effort (I’m not lazy, I’m energy efficient) fun.
Anyway - while back I was building something, and later on needed to document things, but had forgotten to which permission set I’d added permissions to a custom object, and I wasn’t really looking forward to parsing through all of them (about dozen, not even that many)...
…so I pulled up the (nearly) allmighty Salesforce Inspector Reloaded and did a query, a bit like I did earlier:
SELECT Id, Parent.Name
FROM ObjectPermissions
WHERE SObjectType = ‘Custom_Object__c’
…and got a list of ObjectPermission records (and names of their parent Permission Sets), one of which was the one I had added the object’s permissions - and so rather than clicking through the dozen or so custom permission sets, which would have taken me 10 or 20 minutes, this took me about a minute and I got the exact result pretty much instantly.
On the other hand, if you have, say, “inherited” an “organically grown” org or something like that and want to see who has those pesky modify all permissions, you could make that query more specific by adding another selector:
SELECT Id, Parent.Name
FROM ObjectPermissions
WHERE SObjectType = ‘Custom_Object__c’ AND PermissionsModifyAllRecords = true
Now, just as a reminder, those key words don’t need to be capitalized; I do it just out of habit to keep things a bit clearer, and the word wrapping there may or may not happen, but the where statement is meant to be on the same row - not that it needs to be on the same row, SQL, of which the SOQL is a dialect of, is not super picky about it.
Hope you learned something & Happy Hacking 🙂