03 June 2014

Choose your own adventure with custom permissions



The upcoming Summer '14 release notes came out late last week. There were over 330 pages of new features and goodness. However, my favorite feature being announced by far is Custom Permissions (page 172 if you're interested).

What makes this feature one of the coolest ones I've worked on so far is that it enables customers and partners to define their own permissions while enabling administrators to still assign them the same way they assign any other permission on a profile or permission set.

Why use it?

  1. Customers can create permissions for their force.com apps
  2. Customers can create permissions that sync with an authorization directory service like Active Directory or LDAP
  3. IT can store custom metadata about their profiles and permission sets to help categorize them
  4. ISVs (Independent Software Vendors) can create permissions for their apps
  5. Scope Connected apps by retrieving only those permissions assigned to a user for that app without querying for all permissions assigned to the user for the organization

How does this work?


Often times, a salesforce developer will want to create an access check in their code that enables them to differentiate which users can access specific pieces of custom functionality. For instance, only administrators should be allowed access to the Permissioner tab and Visualforce page or only sales managers should be allowed to print the sales commission report. 

There are a variety of ways to create access checks on the salesforce platform. You can re-use an existing access control such as a tab setting or Visualforce page access. However, for everything else, a salesforce developer would have to create something completely custom.

In the past, this has meant creating custom settings which are hierarchical in nature and administered separately from the rest of a user’s permissions. As a result, custom settings do not follow any of the normal behaviors associated with profile or permission set permissions like the ability for an administrator to easily assign them.

Custom permissions enable developers to define new access checks that can be assigned to users the same way as any other user permission: through the user’s permission set or profile. This enables developers to focus on their code, while enabling administrators to manage custom permissions the same way as they manage standard user, object, field, and other kinds of permissions for users. That way the administrator can use point-and-click whereas the developer can use code.

There are two ways custom permission access can be queried in Summer '14 to determine if a user has access:
  1. through SOQL using the SetupEntityAccess and CustomPermissions sObjects to answer whether any user has access to a specific or arbitrary custom permission. 
  2. through the standard Connected Apps flow and the identity service to answer what specific custom permissions the current user has when they authenticate into their connected app.

Usage 1: Use SOQL to determine access with the API



In setup, create a custom permission under Build | Develop | Custom Permissions. 

Query in Workbench using a Developer Edition organization in Summer '14 for all permission sets assigned the 'Approver' permission: 
SELECT Id, DeveloperName,
(select Id, Parent.Name, Parent.Profile.Name from SetupEntityAccessItems)
FROM CustomPermission
WHERE DeveloperName = 'Approver'

Query for all permission sets and profiles with custom permissions:

SELECT Assignee.Name, PermissionSet.Id, PermissionSet.Profile.Name, PermissionSet.isOwnedByProfile, PermissionSet.Label
FROM PermissionSetAssignment
WHERE PermissionSetId
IN (SELECT ParentId
    FROM SetupEntityAccess
    WHERE SetupEntityType = 'CustomPermission')
Query for all SetupEntityAccess rows with custom permissions:

SELECT Id,ParentId,Parent.Name, SetupEntityId FROM SetupEntityAccess
WHERE SetupEntityType='CustomPermission'
AND ParentId
IN (SELECT Id
    FROM PermissionSet
    WHERE isOwnedByProfile = false)

Usage 2: Check access to using Apex



I've heard this use case frequently from customers. Rather than receive an insufficient privileges message after clicking on a button, you can choose whether to display the button based on the user's assigned custom permissions, thereby preventing users from getting an insufficient privilege message after the event.

We determine the permissions that a user has been assigned by first querying all of the Setup Entity Access rows tied to the user’s assigned permission sets where there is at least one row of type ‘CustomPermission’:
access =[SELECT SetupEntityId FROM SetupEntityAccess WHERE SetupEntityType='CustomPermission' AND ParentId IN (SELECT PermissionSetId FROM PermissionSetAssignment WHERE AssigneeId=:userId)];
This usage pattern is more powerful than straight SOQL because it can string the multiple queries together into something that answers whether the user has access to specific custom permissions. 

This sample app was written by John Brock and can be downloaded from his Github repo: https://github.com/john-brock/Custom-Permissions to jump start your custom permission experience.

This feature will be in Developer Preview in Summer '14 which means it will automatically be enabled for all Developer Edition organizations for people to play with and provide feedback for what they want to see.



9 comments:

  1. I am SO excited for this.

    Do you know if there are any plans in the works to allow checking permissions in formula contexts?

    For example, a validation rule that limits who can edit a field: IF(ISCHANGED(mySuperCoolField) && NOT(HASPERMISSION("CanChangeSuperCoolField"))


    Or a custom javascript button that controls access to another page:

    var canModifyPayments = {!HASPERMISSION("CanModifyPayments")};

    if (canModifyPayments) {
    window.open('/apex/ModifyPayments');
    } else {
    alert('You don't have access to the Modify Payments module');
    }

    ReplyDelete
    Replies
    1. Thanks for the great example!! Formula based permission evaluation is being investigated! Stay tuned!!

      Delete
    2. $Permission global variable access to custom permissions is GA in Winter '15. Very nice feature.

      Delete
  2. Thanks for this article!
    For anyone looking for a way to pull the list of custom permissions assigned to the current user in a single query, this is what I've been using.

    SELECT Id, DeveloperName,
    (SELECT SetupEntityId
    FROM SetupEntityAccessItems
    WHERE SetupEntityType='CustomPermission'
    AND ParentId IN (SELECT PermissionSetId
    FROM PermissionSetAssignment
    WHERE AssigneeId=:UserInfo.getUserId()))
    FROM CustomPermission

    Cheers!

    ReplyDelete
  3. Adam, my team is about to implement this for our client. I'd like some recommendations.

    Example 1:
    - User A should be allowed to execute custom buttons 1, 2, 3, 4 on opportunity
    Question: Is it best to create 1 custom permission per each button (function)? Or to create 1 custom permission for the 4 functions combined?

    Example 2:
    - User A should be allowed to execute custom buttons 1, 2, 3, 4
    - User B should be allowed to execute custom buttons 1, 2, 3, 4, 5
    - User A and B share the same profile, each with its own permission set
    Question: Is it best to create custom permissions that are incremental (one custom permission to contain 1 through 4, then another to contain 5)? Or to create custom permissions that are independent of each other?

    ReplyDelete
    Replies
    1. Hi Jo,

      I'm a huge fan of least privilege grouping. So 1, 2, 3, 4 would be group A and 5 would be group B.

      In the future, you may have to devolve 1, 2, 3, 4 and refactor your code; however, in the meantime, it seems like the only variance is between two, not five permissions imho…

      If that were to change in the near term where User C needs access only to 1, 2, 3 or 1 & 2 or just 1, then you should consider breaking it into all five permissions.

      Delete
  4. I have a question, Can we query custom permissions directly to profile, not included permission set in it. If yes Please give me any sample query.

    Thanks in advance

    ReplyDelete
    Replies
    1. Can you provide an example of what you're looking for? Search soql queries on the blog and you should see some samples: http://www.salesforcehacker.com/2013/01/using-soql-to-determine-your-forcecom.html?m=1

      Delete