/
ApexDangerousMethodsRule.java
104 lines (82 loc) · 3.54 KB
/
ApexDangerousMethodsRule.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex.rule.security;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.apex.ast.ASTField;
import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression;
import net.sourceforge.pmd.lang.apex.ast.ASTUserClass;
import net.sourceforge.pmd.lang.apex.ast.ASTVariableDeclaration;
import net.sourceforge.pmd.lang.apex.ast.ASTVariableExpression;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
import net.sourceforge.pmd.lang.apex.rule.internal.Helper;
import net.sourceforge.pmd.lang.rule.RuleTargetSelector;
/**
* Flags dangerous method calls, e.g. FinancialForce
* Configuration.disableTriggerCRUDSecurity() or System.debug with sensitive
* input
*
*
* @author sergey.gorbaty
*
*/
public class ApexDangerousMethodsRule extends AbstractApexRule {
private static final String BOOLEAN = "boolean";
private static final Pattern REGEXP = Pattern.compile("^.*?(pass|pwd|crypt|auth|session|token|saml)(?!id|user).*?$",
Pattern.CASE_INSENSITIVE);
private static final String DISABLE_CRUD = "disableTriggerCRUDSecurity";
private static final String CONFIGURATION = "Configuration";
private static final String SYSTEM = "System";
private static final String DEBUG = "debug";
private final Set<String> whiteListedVariables = new HashSet<>();
@Override
protected @NonNull RuleTargetSelector buildTargetSelector() {
return RuleTargetSelector.forTypes(ASTUserClass.class);
}
@Override
public Object visit(ASTUserClass node, Object data) {
if (Helper.isTestMethodOrClass(node)) {
return data;
}
collectBenignVariables(node);
List<ASTMethodCallExpression> methodCalls = node.descendants(ASTMethodCallExpression.class).toList();
for (ASTMethodCallExpression methodCall : methodCalls) {
if (Helper.isMethodName(methodCall, CONFIGURATION, DISABLE_CRUD)) {
asCtx(data).addViolation(methodCall);
}
if (Helper.isMethodName(methodCall, SYSTEM, DEBUG)) {
validateParameters(methodCall, data);
}
}
whiteListedVariables.clear();
return data;
}
private void collectBenignVariables(ASTUserClass node) {
List<ASTField> fields = node.descendants(ASTField.class).toList();
for (ASTField field : fields) {
if (BOOLEAN.equalsIgnoreCase(field.getType())) {
whiteListedVariables.add(Helper.getFQVariableName(field));
}
}
List<ASTVariableDeclaration> declarations = node.descendants(ASTVariableDeclaration.class).toList();
for (ASTVariableDeclaration decl : declarations) {
if (BOOLEAN.equalsIgnoreCase(decl.getType())) {
whiteListedVariables.add(Helper.getFQVariableName(decl));
}
}
}
private void validateParameters(ASTMethodCallExpression methodCall, Object data) {
List<ASTVariableExpression> variables = methodCall.descendants(ASTVariableExpression.class).toList();
for (ASTVariableExpression var : variables) {
if (REGEXP.matcher(var.getImage()).matches()) {
if (!whiteListedVariables.contains(Helper.getFQVariableName(var))) {
asCtx(data).addViolation(methodCall);
}
}
}
}
}