SFDC Stop - Always the latest about Salesforce


Full Tutorial Series with videos, free apps, live sessions, salesforce consulting and much more.


Telegram logo   Join our Telegram Channel
Showing posts with label PMD. Show all posts
Showing posts with label PMD. Show all posts

Sunday, 8 March 2020

Validate CRUD permission before SOQL/DML operation ? Well...that's History 😎

Hello Trailblazers,

Have you every faced this warning from PMD while writing your apex code which says:-

Validate CRUD permission before SOQL/DML operation (rule: Security-ApexCRUDViolation)
See: https://pmd.github.io/latest/pmd_rules_apex_security.html#apexcrudviolation


Let's have a look at the code in which I am getting this warning. I have to display some contacts in my lightning component. I have created a controller class which will return me the list of contacts based on the limit and offset which are passed as parameters as shown below:-


I am getting the above warning to check CRUD permissions before SOQL from my PMD source code analyzer in VSCode. This warning basically suggests us to make sure that the current user has access to the object and fields that we're accessing or querying before executing the SOQL query. To remove this warning, we need to add a lot of code like:- 


So my final code is shown below:-


And Finally..!! The warning is removed and we're done. But if we carefully have a look, we can see that we have to check for each and every field that we're querying so it can be a lot of code when we're querying a lot of fields or let's say when you have inner queries in an SOQL query, then it'll lead to a lot of extra code just to check permissions.

Thanks to Spring 20 Release, all this is history now 😎 and we can apply Object and Field Level Security in a single line without worrying about writing a lot of code. Let's see how..!!

WITH SECURITY_ENFORCED

This is the best way to make sure that the current user has the access to objects and fields when we're performing a READ operation or SOQL query. All you have to do is to add WITH SECURITY_ENFORCED clause in your SOQL query to enable object and field level permissions check.

Let's have a look at the updated code below:-

As you can see above, I have applied WITH SECURITY_ENFORCED after Contact in my query and that's all. This query will return a QueryException if we're querying a field which the current user doesn't have access to. To check that, I removed access from Phone field and called getContacts method from anonymous apex window. As you can see in the code, I am displaying the message from query exception using the getMessage() method. So, I got this message when I called the method after removing the access to the Phone field of Contact:- Insufficient permissions: secure query included inaccessible field.
So, in this way, we can perform a secure SOQL query and we don't have to check for any object or field level permissions. All that is already included in the query itself.

Some points to remember when using WITH SECURITY_ENFORCED clause:-

  1. It's only applicable when you want to check for READ access.
  2. If we have a WHERE clause, we'll have WITH SECURITY_ENFORCED clause after the WHERE clause, otherwise it'll be after the FROM clause as shown in the query in the above code.
  3. It is always applied before any ORDER BY, LIMIT, OFFSET clauses as you can see above we have applied it before the LIMIT and OFFSET clause.
  4. It can also be applied in  aggregate queries returning list of AggregateResult.
  5. Even if you have inner queries, you can have a single WITH SECURITY_ENFORCED in the outer query itself and it'll work for inner query fields.
  6. If you're accessing fields from parent object relationships WITH SECURITY_ENFORCED will work in that too, like:- if we are querying Account.Phone in our query above and we don't have access to phone field of account, it'll throw the same error. Make sure that it'll not work in some lookup fields like:- Owner, CreatedBy, LastModifiedBy.
  7. It'll not work if you have TYPEOF expressions in your queries.
  8. If you're creating an appexchange app, make sure the API version is 48.0 or later as this feature is Generally Available in this api version.

For more information on WITH SECURITY_ENFORCED have a look at the documentaton here:- https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_with_security_enforced.htm

stripInaccessible()

This method is mainly used to strip the fields from results of a query or subquery that the user doesn't  have access to. The stripInaccessible method is defined in Security class and has two syntax as given below:-

1. stripInaccessible(accessCheckType, sourceRecords, enforceRootObjectCRUD):- In this method, we have 3 parameters:-
  •  accessCheckType:- This is the access type parameter of the type AccessType enum. There are 4 values namely:- CREATABLE, READABLE, UPDATABLE and UPSERTABLE.
  • sourceRecords:- This is basically the list of sobjects in which we have to remove fields that are inaccessible by the user.
  • enforceRootObjectCRUD:- This is an optional boolean variable in which you specify wether you need to check for object level access or not. The default value of this parameter is true

2. stripInaccessible(accessCheckType, sourceRecords):- In this method, we have 2 parameters that are the same as described in above method. The only difference here is that while using this method, we're not checking for object level access.

I have updated my ContactsController class code and you can see that below:-

As you can see above, I have queried the list of contacts, displayed them and then checking the READ access on the list of contacts that I have queried. I have also specified the third parameter as true so that it'll check for the object accessibility as well. The stripInaccessible() method will return an object of SObjectAccessDecision class which is stored in the decision variable. This class has mainly 3 methods which we've called. The 3 methods are:-
  • getModifiedIndexes() :- As you know that we pass a list of sobject in the second parameter. So, let's say we have 10 records out of which 5 of them have a value in Phone field which is inaccessible by the user. So, this method will return the indexes i.e. Set<Integer> i.e. the indexes in the list of sobjects on which those 5 records are present and have value in Phone field.
  • getRecords() :- This method will return the modified list of sObjects after stripping the fields that are inaccessible by the user.
  • getRemovedFields() :- This method will return a Map<String, Set<String>> in which the keys are basically the sObject names and values are Set<String> which are the field API names that are stripped from the records. This is mainly useful when you have subqueries, so that you can see which of the fields are stripped from each object.
I executed the above method in the anonymous window as shown below and I have removed access from Phone field of Contact.


I checked the debug messages and got messages in the debug as shown below :-

As you can see in the debug above, I have queried the list of contacts in which only the 3rd contact has a phone number. This 3rd contact will be at index 2 in the list. Therefore, getModifiedIndexes() is returning the index as 2 as only that contact is modified. The getRecords() method has returned the modified list of records in which you can see that the phone number is stripped from the 3rd record. Also, the getRemovedFields() method is returning the object name as key which is Contact in our case and the Set of fields that are removed which is Phone in our case.

I also tried removing the contact object access from the user and executed the method. I received the below NoAccessException in that case as shown below:-

System.NoAccessException: No access to entity Class.System.Security.stripInaccessible: line 15, column 1 Class.ContactsController.getContacts: line 15, column 1 

Similarly, if you're trying to create/update a record, you'll get a NoAccessException in case you don't have access to that record. You can wrap this line in a try block and have a catch(NoAccessException e) in order to catch the NoAccessException. You can also use the stripInaccessible() method with two parameters so that you can strip the fields in list of records and have a noaccess exception check only covering the insert/update/upsert statement in a try catch block.

Note:- The stripInaccessible() method doesn't support AggregateResult SObject type. So, make sure you don't pass the records of type AggregateResult otherwise an exception will be thrown.

That's all for this post. If you liked this post, make sure to share it in your network and let me know your feedback in the comments down below.

Happy Trailblazing..!!

Saturday, 16 December 2017

Analyze your Apex code using PMD Source Code Analyzer

As a salesforce developer, we all write apex code or even if you are an admin, there are some conditions when you have to write code or even some triggers. So, isn't it awesome if you can write code that's perfect and follow the industry standards ?

Consider a situation when you have to solve a problem to get a particular task done and you start writing your apex code for that. After some time, you finally completed your code. You analyzed it using a free tool and it is telling you that here are the points where your code is not following the standards or it is not properly optimized. Now what ? Your next step will be asking your friends or take the help of Trailblazer Community to make your code perfect and optimized. As a result, it not only improved your code performance but also improved your skills. So, that in future if somebody looks at your code, He/She will be impressed by looking at your perfect style of writing code. Great !

What is PMD ?

PMD basically stands for Programming Mistake Detector. It is a source code analyzer that finds common mistakes in your code like:- unused variables, if-else statements without braces, naming conventions of methods, soql in loops and many more. It also includes CPD which stands for Copy/Paste Detector which finds duplicate code in your files and make you aware so that you can improve to make your code reusable.


Setting up PMD

You can download the latest version of PMD as a zip file from the PMD Homepage by clicking the download link or you can scroll down to the downloads section and download any other version from there. Currently, the latest version is 6.0.0 which was released yesterday. You can download it directly here.

After downloading the zip file you have to extract it and it will give you two folders namely bin and lib apart from a LICENSE file. I am currently using a windows operating system so going to tell you the commands according to that. If you are using a Linux/Unix OS you can read from here and then follow the similar commands according to your OS from the getting started page.

In the bin folder, we get a number of batch files out of which - pmd.bat and cpd.bat files are the one which we'll be mainly using for using pmd. As PMD is a command line tool, so if you want to use it like from anywhere on your system, I suggest you to add pmd bin to your system path in the environment variables so that it can be accessed from anywhere on your system. That's all for setting up let's learn how to use PMD.

Analyzing code using PMD

Now you have installed PMD and you want to analyze your code. PMD allows you to analyze code written in a number of languages like:- java, javascript, xml, apex etc. We'll mainly focus on the apex code here. So here is the general command syntax to analyze the apex class or a directory consisting of a number of classes as follows:- 


The release 6.0.0 is the latest and is a major release so even if you are already using PMD, this release consists of a number of changes that you must be aware of. Even the apex rules categorization is updated and the old rule-sets like:- Braces, Complexity is deprecated now. You can know about the latest apex rules in the current release of PMD here. The table of contents present on this page have the same name as the xml files present in the pmd library implementing the rules under that name. Below is the example command using the default rules already present in pmd library for apex. It is using the design.xml rule file under the apex category following the name of the rule that you want to check.You can run the command without any rule name to use all the rules present in that xml file.

This command is checking that in all the apex classes present in the classes folder. If there is any class which is using methods with excessive parameters. The excessive parameter rule is present in the standard library and you can view it here. So, when I run this command as I have set the format as html and the output file is named output.html, I get the file named output.html in the current directory where the command is executed as I have not given any path for output.html but you can keep a separate path for output report files.
The report created by pmd for me is an html file which looks like this:-

The report gives you the file name with path, the line number that consists of error as well as the problem which is the direct link to the original doc where the sample error code is there to which your code resemble leading to error. When I opened my test.cls then this was the code snippet giving me error:-

As you can see this method consists of a number of parameters whereas it is preffered that you use less parameters in your method. So this is how you can use pmd with some general standard rules defined in the library to check whether your code quality is good or not.

Apart from people working as a developer or admin, if you are a technical architect or even the owner of your company. Then obviously you want people working under you to write perfect code and maybe follow only a bunch of standard rules that you think are most important. Don't worry PMD has taken care of that too.

You can make your own rule file in which you can define a bunch of standard rules and then distribute it to other developers so that they must follow the standards while writing code.
You can see in the file below that I am using three common ways by which you can add rules to your rule-set file.
  1. By using a single rule from a rule-set.
  2. By using full rule-set present in the library.
  3. By using full rule-set but excluding some of the rules from it.
In this way, you can make your own rule-set file and you can use that file as follows:-


Try the above command by copying the rule-set file given above or making your own rule-set file and start analyzing your code.

CPD - Copy/Paste Detector

CPD is another feature of PMD that you can use to analyze the re-usability implemented in your code. It scans your files and detects duplicate code for you. The general syntax for the CPD command is as follows:-

Below is the example command for the above syntax that I used to find duplicate code in my files:-

I have set the minimum tokens to 5 and specifically used my test.cls as I have added a lot of duplicate code in that. So, you can see the output from cpd below:-


As you can see above, I have duplicated System.log('function with excessive parameters'); and also the doWork() by writing it as doMoreWork() with multiple integers, as the number of minimum tokens I specified in cpd command are very less i.e. 5 so cpd is reporting it as duplicate code.

Even if you don't like to use command line, PMD has made a cpdgui that you can use to find duplicate code in your directory and you can even simply export your report to text, xml or csv formats.
Just go to the command line into your bin folder and type cpdgui.bat and you will see an application like this:-


In the application, select the folder in which your classes are present and change value in report duplicate chunks larger than field the default value is 75. It is similar to minimum tokens you have in cmd. Select the language as apex and click on go. You have a report like the one shown below and you have the option to export that too.


If you want to learn more about CPD you can checkout the docs here. So, now you learned how you can analyze your code usind PMD Source Code Analyzer and also how you can detect duplicate code using CPD - Copy Paste Detector tool from PMD.

Let's start using PMD now and be sure that you always write quality code.