I have been wanting to explore Custom Permissions for a little while now, since they are now GA in Winter’15 i thought its about time i got stuck in. Profiles, Permission Sets have until recently, been focusing on granting permissions to entities only known to the platform, such as objects, fields, Apex classes and Visualforce pages. In most cases these platform entities map to a specific feature in your application you want to provide permission to access.
However there are cases where this is not always that simple. For example consider a Visualforce page you that controls a given process in your application, it has three buttons on it Run, Clear History and Reset. You can control access to the page itself, but how do you control access to the three buttons? What you need is to be able to teach Permission Sets and Profiles about your application functionality, enter Custom Permissions!
NOTE: That you can also define dependencies between your Custom Permissions, for example Clear History and Reset permissions might be dependent on a Manage Important Process custom permission in your package.
Once these have been created, you can reference them in your packaged Permission Sets and since they are packaged themselves, they can also be referenced by admins managing your application in a subscriber org.
The next step is to make your code react to these custom permissions being assigned or not.
New Global Variable $Permission
You can use the $Permission from a Visualforce page or as SFDCWizard points out here from Validation Rules! Here is the Visualforce page example given by Salesforce in their documentation.
<apex:pageBlock rendered="{!$Permission.canSeeExecutiveData}"> <!-- Executive Data Here --> </apex:pageBlock>
Referencing Custom Permissions from Apex
IMPORTANT UPDATE: Since API 41 (Winter’18) there is now a native way to read Custom Permissions. The following may still be useful if you have requirements not met by the native method. FeatureManagement.checkPermission.
In the case of object and field level permissions, the Apex Describe API can be used to determine if an object or field is available and for what purpose, read or edit for example. This is not going help us here, as custom permissions are not related to any specific object or field. The solution is to leverage the Permission Set Object API to query the SetupEntityAccess and CustomPermission records for Permission Sets or Profiles that are assigned to the current user.
The following SOQL snippets are from the CustomPermissionsReader class i created to help with reading Custom Permissions in Apex (more on this later). As you can see you need to run two SOQL statements to get what you need. The first to get the Id’s the second to query if the user actually has been assigned a Permission Set with them in.
List<CustomPermission> customPermissions = [SELECT Id, DeveloperName FROM CustomPermission WHERE NamespacePrefix = :namespacePrefix]; List<SetupEntityAccess> setupEntities = [SELECT SetupEntityId FROM SetupEntityAccess WHERE SetupEntityId in :customPermissionNamesById.keySet() AND ParentId IN (SELECT PermissionSetId FROM PermissionSetAssignment WHERE AssigneeId = :UserInfo.getUserId())];
Now personally i don’t find this approach that appealing for general use, firstly the Permission Set object relationships are quite hard to get your head around and secondly we get charged by the platform to determine security through the SOQL governor. As a good member of the Salesforce community I of course turned my dislike into an Idea “Native Apex support for Custom Permissions” and posted it here to recommend Salesforce include a native class for reading these, similar to Custom Labels for example.
Introducing CustomPermissionReader
In the meantime I have set about creating an Apex class to help make querying and using Custom Permissions easier. Such a class might one day be replaced if my Idea becomes a reality or maybe its internal implementation just gets improved. One things for sure, i’d much rather use it for now than seed implicit SOQL’s throughout a code base!
Its pretty straight forward to use, construct it in one of two ways, depending if you want all non-namespaced Custom Permissions or if your developing a AppExchange package, give it any one of your packaged Custom Objects and it will ensure that it only ever reads the Custom Permissions associated with your package.
You can download the code and test for CustomPermissionsReader here.
// Default constructor scope is all Custom Permissions in the default namespace CustomPermissionsReader cpr = new CustomPermissionsReader(); Boolean hasPermissionForReset = cpr.hasPermission('Reset'); // Alternative constructor scope is Custom Permissions that share the // same namespace as the custom object CustomPermissionsReader cpr = new CustomPermissionsReader(MyPackagedObject.SObjectType); Boolean hasPermissionForReset = cpr.hasPermission('Reset');
Like any use of SOQL we must think in a bulkified way, indeed its likely that for average to complex peaces of functionality you may want to check at least two or more custom permissions once you get started with them. As such its not really good practice to make single queries in each case.
For this reason the CustomPermissionsReader was written to load all applicable Custom Permissions and act as kind of cache. In the next example you’ll see how i’ve leveraged the Application class concept from the Apex Enterprise Patterns conventions to make it a singleton for the duration of the Apex execution context.
Here is an example of an Apex test that creates a PermissionSet, adds the Custom Permission and assigns it to the running user to confirm the Custom Permission was granted.
@IsTest private static void testCustomPermissionAssigned() { // Create PermissionSet with Custom Permission and assign to test user PermissionSet ps = new PermissionSet(); ps.Name = 'Test'; ps.Label = 'Test'; insert ps; SetupEntityAccess sea = new SetupEntityAccess(); sea.ParentId = ps.Id; sea.SetupEntityId = [select Id from CustomPermission where DeveloperName = 'Reset'][0].Id; insert sea; PermissionSetAssignment psa = new PermissionSetAssignment(); psa.AssigneeId = UserInfo.getUserId(); psa.PermissionSetId = ps.Id; insert psa; // Create reader CustomPermissionsReader cpr = new CustomPermissionsReader(); // Assert the CustomPermissionsReader confirms custom permission assigned System.assertEquals(true, cpr.hasPermission('Reset')); }
Seperation of Concerns and Custom Permissions
Those of you familiar with using Apex Enterprise Patterns might be wondering where checking Custom Permission fits in terms of separation of concerns and the layers the patterns promote.
The answer is at the very least in or below the Service Layer, enforcing any kind of security is the responsibility of the Service layer and callers of it are within their rights to assume it is checked. Especially if you have chosen to expose your Service layer as your application API.
This doesn’t mean however you cannot improve your user experience by using it from within Apex Controllers, Visualforce pages or @RemoteAction methods to control the visibility of related UI components, no point in teasing the end user!
Integrating CustomerPermissionsReader into your Application class
The following code uses the Application class concept i introduced last year and at Dreamforce 2014, which is a single place to access your application scope concepts, such as factories for selectors, domain and service class implementations (it also has a big role to play when mocking).
public class Application { /** * Expoeses typed representation of the Applications Custom Permissions **/ public static final PermissionsFactory Permissions = new PermissionsFactory(); /** * Class provides a typed representation of an Applications Custom Permissions **/ public class PermissionsFactory extends CustomPermissionsReader { public Boolean Reset { get { return hasPermission('Reset'); } } } }
This approach ensures their is only one instance of the CustomPermissionsReader per Apex Execution context and also through the properties it exposes gives a compiler checked way of referencing the Custom Permissions, making it easier for application developers code to access them.
if(Application.Permissions.Reset) { // Do something to do with Reset... }
Finally, as a future possibility, this approach gives a nice injection point for mocking the status of Custom Permissions in your Apex Unit tests, rather than having to go through the trouble of setting up a Permission Set and assigning it in your test code every time as shown above.
Call to Action: Ideas to Upvote
While writing this blog I created one Idea and came across a two others, i’d like to call you the reader to action on! Please take a look and of course only if you agree its a good one, give it the benefit of your much needed up vote!
- Idea: Make a “PackageInfo” Apex class available for managed code to call at runtime
- Idea: Display the Profiles & Permissions Sets with Custom Permissions on Page
- Idea: Native Apex support for Custom Permissions
January 14, 2015 at 9:46 pm
Nice, this will come in handy until some of those ideas get implemented. I wrote a similar utility for reverse searching profiles and permission sets. This could be used for listing the profiles and permission sets for a particular custom permission. A stop gap tool till something gets implemented in the platform. https://kksfblog.wordpress.com/2015/01/08/salesforce-metadata-analyzer-audit-all-you-want/
January 15, 2015 at 9:09 pm
Nice thanks for sharing!
January 25, 2015 at 3:43 pm
Reblogged this on SutoCom Solutions.
February 4, 2015 at 4:08 am
I may be missing something here, but will the reader class picks up CustomPermissions if they are directly added to the profile, without using Permission sets?
February 4, 2015 at 8:18 pm
Yes it will, Profiles are actually stored as read-only Permission Sets by the platform. So the same queries apply.
April 27, 2016 at 8:35 am
Hi Andrew, have you tried using Custom Permissions with Validation Rules and noticed any performance issues ? Have a look at this post: https://www.salesfix.com.au/custom-permissions-validation-rules-and-apex-cpu-limits/ I’d appreciate your comments.
April 27, 2016 at 12:11 pm
Wow, this has to be a bug in my view, not that it carries “some” overhead so much, but that there is not Apex in sight and that the overhead is not something I would consider acceptable (I have just read your post briefly while traveling).
August 5, 2016 at 6:41 am
Hi Andrew. While migration class where i am using customPermissionsReader i am facing below error (change set migration from sandbox to sandbox)
Invalid type: customPermissionsReader
Also i tried to copy paste code from one org to other org but still same issue. I did created custom permission in org and gave access to profile. Could you please help me what might be the cause
August 5, 2016 at 2:43 pm
Did you include that class in the changeset?
January 25, 2017 at 8:51 pm
@Andrew – Thanks for this. I’ll be making use of it. However, I have a questions. What are the advantages of using a Custom Permission vs. Hierarchical Custom Setting. It seems a custom setting might achieve the same as a custom permission. If I remember correctly, custom settings don’t count against Query Limit. However, I’m not sure if you can use custom setting in Validation rule too. Maybe that’s the benefit of a Custom Permission. Any thoughts?
February 16, 2017 at 2:07 am
The two are different things. One is helping you implement your own security checks, the other is a storage solution for your configuration.
April 7, 2017 at 3:21 am
When a user is using our app, we need to check a certain Custom Permission. However, these users are getting the error “No access to SetupEntityAccess” when our APEX code checks to see if they have a certain custom permission. If we enable “View Setup & Configuration” in their profile or PS, they don’t get this error. Does that mean that these users MUST be given “View Setup” in order to make use of custom permissions, or is this permission required?
I would assume the CustomPermissionReader class would be bound by this same restriction if that’s the case. Right? Or am I missing something? Is there some way around having the “View Setup” permission that I’m just not aware of?
April 7, 2017 at 7:43 am
Is your code reading the SetupEntjtyAcesss object?
April 27, 2017 at 8:51 pm
Hi Andrew, nice write up. I’ve used Custom Permissions in VF in the past and am now evaluating using them in Lighting Components. I don’t believe the LCF supports $Permission (yet) – is this your understanding as well? In order to leverage custom permissions in a Lightning Component do we need to go to Apex like you’ve modeled here? BTW – picked up the latest version of your book. Nice work.
May 6, 2017 at 1:57 am
That is indeed the current case, you will have to do this via a apex controller. https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/expr_source.htm. Glad you picked up the book! Enjoy! 🙂
June 1, 2017 at 9:39 am
for those of us who have adopted fflib, why not add fflib_CustomPermissionsReader.cls including updating the fflib_Application.cls? Then we have mock support builtin on a par with the other layers.
June 1, 2017 at 10:24 pm
Good idea, happy to accept a PR for this if you fancy, otherwise please log the issue as an enhancement and I will take a look next time I have a burst of time
Pingback: Custom Permissions, Validation Rules and Apex CPU Limits - SalesFix
August 11, 2019 at 11:32 pm
Hi Andrew,
This is indeed a great article. Glad I was able to refer for my current problem.
I have a requirement where I need to check for permission set in lookup filter which I see is not possible. So I am trying to create a formula field on the user that can read if the user is assigned the permission set and use this field in the lookup filter.
Actually I am creating custom permission and have it assigned to the permission set. Now in the formula field on the user I am trying to check if the user has this custom permission from the assigned permission set – IF($permission.custom_Permission, ‘isAssigned’, ‘noAccess’) – but this is always giving me noAccess even when I have assigned the permission set to the user. I am not sure where I am doing wrong.
If it could work I can then use this formula field in the lookup filter.
Can you give some light to achieve this? Is there an alternative to achieve this?
Thanks
September 2, 2019 at 7:53 am
Perhaps try to output the value of the $permisson.custom_permission just as a text formula field so you can see its value, maybe it’s not the value your logic is expecting?
Pingback: Custom Permissions, Validation Rules and Apex CPU Limits – SalesFix