[apex] avoid hardcoding id's

This commit is contained in:
Jan Aertgeerts
2017-10-09 23:24:47 +02:00
parent 8d808049f3
commit 6989b45067
6 changed files with 171 additions and 1 deletions

View File

@ -5,7 +5,7 @@ permalink: pmd_rules_apex_security.html
folder: pmd/rules/apex
sidebaractiveurl: /pmd_rules_apex.html
editmepath: ../pmd-apex/src/main/resources/rulesets/apex/security.xml
keywords: Security, ApexSharingViolations, ApexOpenRedirect, ApexInsecureEndpoint, ApexXSSFromURLParam, ApexXSSFromEscapeFalse, ApexBadCrypto, ApexCSRF, ApexSOQLInjection, ApexCRUDViolation, ApexDangerousMethods, ApexSuggestUsingNamedCred
keywords: Security, ApexSharingViolations, ApexOpenRedirect, ApexInsecureEndpoint, ApexXSSFromURLParam, ApexXSSFromEscapeFalse, ApexBadCrypto, ApexCSRF, ApexSOQLInjection, ApexCRUDViolation, ApexDangerousMethods, ApexSuggestUsingNamedCred, AvoidHardcodingId
---
## ApexBadCrypto
@ -412,3 +412,41 @@ public without sharing class Foo {
<rule ref="rulesets/apex/security.xml/ApexXSSFromURLParam" />
```
## AvoidHardcodingId
**Since:** PMD 6.0.0
**Priority:** Medium (3)
When deploying Apex code between sandbox and production environments, or installing Force.com AppExchange packages, it is essential to avoid hardcoding IDs in the Apex code. By doing so, if the record IDs change between environments, the logic can dynamically identify the proper data to operate against and not fail.
**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.security.AvoidHardcodingIdRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/AvoidHardcodingIdRule.java)
**Example(s):**
``` java
public without sharing class Foo {
for(Account a: Trigger.new){
//Error - hardcoded the record type id
if(a.RecordTypeId=='012500000009WAr'){
//do some logic here.....
} else if(a.RecordTypeId=='0123000000095Km'){
//do some logic here for a different record type...
}
}
}
```
**This rule has the following properties:**
|Name|Default Value|Description|
|----|-------------|-----------|
|cc_categories|[Style]|Code Climate Categories|
|cc_remediation_points_multiplier|1|Code Climate Remediation Points multiplier|
|cc_block_highlighting|false|Code Climate Block Highlighting|
**Use this rule by referencing it:**
``` xml
<rule ref="rulesets/apex/security.xml/AvoidHardcodingId" />
```

View File

@ -0,0 +1,42 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex.rule.security;
import java.util.regex.Pattern;
import net.sourceforge.pmd.lang.apex.ast.ASTAssignmentExpression;
import net.sourceforge.pmd.lang.apex.ast.ASTLiteralExpression;
import net.sourceforge.pmd.lang.apex.ast.AbstractApexNode;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
public class AvoidHardcodingIdRule extends AbstractApexRule {
private static final Pattern PATTERN = Pattern.compile("^[a-zA-Z0-9]{5}[0][a-zA-Z0-9]{9,12}$", Pattern.CASE_INSENSITIVE);
public AvoidHardcodingIdRule() {
setProperty(CODECLIMATE_CATEGORIES, "Security");
setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100);
setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false);
}
@Override
public Object visit(ASTAssignmentExpression node, Object data) {
findHardcodedId(node, data);
return data;
}
private void findHardcodedId(AbstractApexNode<?> node, Object data) {
ASTLiteralExpression literalNode = node.getFirstChildOfType(ASTLiteralExpression.class);
if (literalNode != null) {
Object o = literalNode.getNode().getLiteral();
if (o instanceof String) {
String literal = (String) o;
if (PATTERN.matcher(literal).matches()) {
addViolation(data, literalNode);
}
}
}
}
}

View File

@ -287,6 +287,15 @@
<property name="cc_block_highlighting" value="false"/>
</properties>
</rule>
<rule ref="rulesets/apex/security.xml/AvoidHardcodingId" message="Avoid hardcoding ID's">
<priority>3</priority>
<properties>
<!-- relevant for Code Climate output only -->
<property name="cc_categories" value="Security"/>
<property name="cc_remediation_points_multiplier" value="20"/>
<property name="cc_block_highlighting" value="false"/>
</properties>
</rule>
<!-- BRACES -->
<rule ref="rulesets/apex/braces.xml/IfStmtsMustUseBraces" message="Avoid using if statements without curly braces">
<priority>3</priority>

View File

@ -272,4 +272,31 @@ public class Foo {
</example>
</rule>
<rule name="AvoidHardcodingId"
since="6.0.0"
message="Hardcoding Id's is bound to break when changing environments."
class="net.sourceforge.pmd.lang.apex.rule.security.AvoidHardcodingIdRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_security.html#avoidhardcodingid">
<description>
When deploying Apex code between sandbox and production environments, or installing Force.com AppExchange packages,
it is essential to avoid hardcoding IDs in the Apex code. By doing so, if the record IDs change between environments,
the logic can dynamically identify the proper data to operate against and not fail.
</description>
<priority>3</priority>
<example>
<![CDATA[
public without sharing class Foo {
void foo() {
//Error - hardcoded the record type id
if(a.RecordTypeId == '012500000009WAr'){
//do some logic here.....
} else if(a.RecordTypeId == '0123000000095Km'){
//do some logic here for a different record type...
}
}
}
]]>
</example>
</rule>
</ruleset>

View File

@ -23,5 +23,6 @@ public class SecurityRulesTest extends SimpleAggregatorTst {
addRule(RULESET, "ApexCRUDViolation");
addRule(RULESET, "ApexDangerousMethods");
addRule(RULESET, "ApexSuggestUsingNamedCred");
addRule(RULESET, "AvoidHardcodingId");
}
}

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<test-data
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description>Non compliant scenario: Hardcoded Id</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
public void method (ID newRecordID) {
for (Account current : listOfcounts){
if (current.getId == 'a002400000RG1nyAAD') {
}
}
method('3266sd35435sd6a');
}
}
]]></code>
</test-code>
<test-code>
<description>Compliant scenario, getting ID dynamically</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
public void method (ID newRecordID) {
for (Account current : listOfcounts){
if (current.getId == newRecordID) {
}
}
otherMethod(newRecordID);
}
}
]]></code>
</test-code>
<test-code>
<description>Test for random string combinations</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
void foo() {
return 'jatuatzbtazi124';
}
}
]]></code>
</test-code>
</test-data>