"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexCRUDViolationRule.java" between
pmd-src-6.37.0.zip and pmd-src-6.38.0.zip

About: PMD is a source code analyzer for Java, JavaScript, XML and others. It finds unused variables, empty catch blocks, unnecessary object creation, and so forth. Sources (Java).

ApexCRUDViolationRule.java  (pmd-src-6.37.0):ApexCRUDViolationRule.java  (pmd-src-6.38.0)
skipping to change at line 21 skipping to change at line 21
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.WeakHashMap; import java.util.WeakHashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.apex.ast.ASTAssignmentExpression; import net.sourceforge.pmd.lang.apex.ast.ASTAssignmentExpression;
import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement; import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTDmlDeleteStatement; import net.sourceforge.pmd.lang.apex.ast.ASTDmlDeleteStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTDmlInsertStatement; import net.sourceforge.pmd.lang.apex.ast.ASTDmlInsertStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTDmlMergeStatement; import net.sourceforge.pmd.lang.apex.ast.ASTDmlMergeStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpdateStatement; import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpdateStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpsertStatement; import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpsertStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTField; import net.sourceforge.pmd.lang.apex.ast.ASTField;
import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclaration; import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclarationStatements; import net.sourceforge.pmd.lang.apex.ast.ASTFieldDeclarationStatements;
skipping to change at line 88 skipping to change at line 89
"isAuthorizedToCreate", }; "isAuthorizedToCreate", };
private static final String[] ESAPI_ISAUTHORIZED_TO_UPDATE = new String[] { "ESAPI", "accessController", private static final String[] ESAPI_ISAUTHORIZED_TO_UPDATE = new String[] { "ESAPI", "accessController",
"isAuthorizedToUpdate", }; "isAuthorizedToUpdate", };
private static final String[] ESAPI_ISAUTHORIZED_TO_DELETE = new String[] { "ESAPI", "accessController", private static final String[] ESAPI_ISAUTHORIZED_TO_DELETE = new String[] { "ESAPI", "accessController",
"isAuthorizedToDelete", }; "isAuthorizedToDelete", };
private static final String[] RESERVED_KEYS_FLS = new String[] { "Schema", S _OBJECT_TYPE, }; private static final String[] RESERVED_KEYS_FLS = new String[] { "Schema", S _OBJECT_TYPE, };
private static final Pattern WITH_SECURITY_ENFORCED = Pattern.compile("(?is) .*[^']\\s*WITH\\s+SECURITY_ENFORCED\\s*[^']*"); private static final Pattern WITH_SECURITY_ENFORCED = Pattern.compile("(?is) .*[^']\\s*WITH\\s+SECURITY_ENFORCED\\s*[^']*");
private final Map<String, String> varToTypeMapping = new HashMap<>(); private Map<String, String> varToTypeMapping;
private final ListMultimap<String, String> typeToDMLOperationMapping = Array private ListMultimap<String, String> typeToDMLOperationMapping;
ListMultimap.create(); private Map<String, String> checkedTypeToDMLOperationViaESAPI;
private final Map<String, String> checkedTypeToDMLOperationViaESAPI = new Ha private Map<String, ASTMethod> classMethods;
shMap<>();
private final Map<String, ASTMethod> classMethods = new WeakHashMap<>();
private String className; private String className;
public ApexCRUDViolationRule() { public ApexCRUDViolationRule() {
setProperty(CODECLIMATE_CATEGORIES, "Security"); setProperty(CODECLIMATE_CATEGORIES, "Security");
setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100);
setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false);
} }
@Override @Override
public void start(RuleContext ctx) {
// At the start of each rule execution, these member variables need to b
e fresh. So they're initialized in the
// .start() method instead of the constructor, since .start() is called
before every execution.
varToTypeMapping = new HashMap<>();
typeToDMLOperationMapping = ArrayListMultimap.create();
checkedTypeToDMLOperationViaESAPI = new HashMap<>();
classMethods = new WeakHashMap<>();
className = null;
super.start(ctx);
}
@Override
public Object visit(ASTUserClass node, Object data) { public Object visit(ASTUserClass node, Object data) {
if (Helper.isTestMethodOrClass(node) || Helper.isSystemLevelClass(node)) { if (Helper.isTestMethodOrClass(node) || Helper.isSystemLevelClass(node)) {
return data; // stops all the rules return data; // stops all the rules
} }
className = node.getImage(); className = node.getImage();
for (ASTMethod n : node.findDescendantsOfType(ASTMethod.class)) { for (ASTMethod n : node.findDescendantsOfType(ASTMethod.class)) {
StringBuilder sb = new StringBuilder().append(n.getDefiningType()).a ppend(":") StringBuilder sb = new StringBuilder().append(n.getDefiningType()).a ppend(":")
.append(n.getCanonicalName()).append(":") .append(n.getCanonicalName()).append(":")
skipping to change at line 249 skipping to change at line 262
return data; return data;
} }
@Override @Override
public Object visit(final ASTForEachStatement node, Object data) { public Object visit(final ASTForEachStatement node, Object data) {
final ASTSoqlExpression soql = node.getFirstChildOfType(ASTSoqlExpressio n.class); final ASTSoqlExpression soql = node.getFirstChildOfType(ASTSoqlExpressio n.class);
if (soql != null) { if (soql != null) {
checkForAccessibility(soql, data); checkForAccessibility(soql, data);
} }
return data; return super.visit(node, data);
} }
private void addVariableToMapping(final String variableName, final String ty pe) { private void addVariableToMapping(final String variableName, final String ty pe) {
switch (type.toLowerCase(Locale.ROOT)) { switch (type.toLowerCase(Locale.ROOT)) {
case "list": case "list":
case "map": case "map":
break; break;
default: default:
varToTypeMapping.put(variableName, getSimpleType(type)); varToTypeMapping.put(variableName, getSimpleType(type));
break; break;
skipping to change at line 541 skipping to change at line 554
StringBuilder sb = new StringBuilder().append(node.getDefini ngType()) StringBuilder sb = new StringBuilder().append(node.getDefini ngType())
.append(":").append(identifiers.get(0)); .append(":").append(identifiers.get(0));
checkedTypeToDMLOperationViaESAPI.put(sb.toString(), dmlOper ation); checkedTypeToDMLOperationViaESAPI.put(sb.toString(), dmlOper ation);
} }
} }
} }
} }
private void validateCRUDCheckPresent(final ApexNode<?> node, final Object d ata, final String crudMethod, private boolean validateCRUDCheckPresent(final ApexNode<?> node, final Objec t data, final String crudMethod,
final String typeCheck) { final String typeCheck) {
boolean missingKey = !typeToDMLOperationMapping.containsKey(typeCheck); boolean missingKey = !typeToDMLOperationMapping.containsKey(typeCheck);
boolean isImproperDMLCheck = !isProperESAPICheckForDML(typeCheck, crudMe thod); boolean isImproperDMLCheck = !isProperESAPICheckForDML(typeCheck, crudMe thod);
boolean noSecurityEnforced = !isWithSecurityEnforced(node); boolean noSecurityEnforced = !isWithSecurityEnforced(node);
if (missingKey) { if (missingKey) {
//if condition returns true, add violation, otherwise return. //if condition returns true, add violation, otherwise return.
if (isImproperDMLCheck && noSecurityEnforced) { if (isImproperDMLCheck && noSecurityEnforced) {
addViolation(data, node); addViolation(data, node);
return true;
} }
} else { } else {
boolean properChecksHappened = false; boolean properChecksHappened = false;
List<String> dmlOperationsChecked = typeToDMLOperationMapping.get(ty peCheck); List<String> dmlOperationsChecked = typeToDMLOperationMapping.get(ty peCheck);
for (String dmlOp : dmlOperationsChecked) { for (String dmlOp : dmlOperationsChecked) {
if (dmlOp.equalsIgnoreCase(crudMethod)) { if (dmlOp.equalsIgnoreCase(crudMethod)) {
properChecksHappened = true; properChecksHappened = true;
break; break;
} }
if (ANY.equals(crudMethod)) { if (ANY.equals(crudMethod)) {
properChecksHappened = true; properChecksHappened = true;
break; break;
} }
} }
if (!properChecksHappened) { if (!properChecksHappened) {
addViolation(data, node); addViolation(data, node);
return true;
} }
} }
return false;
} }
private void checkForAccessibility(final ASTSoqlExpression node, Object data ) { private void checkForAccessibility(final ASTSoqlExpression node, Object data ) {
final Set<String> typesFromSOQL = getTypesFromSOQLQuery(node); final Set<String> typesFromSOQL = getTypesFromSOQLQuery(node);
final Set<ASTMethodCallExpression> prevCalls = getPreviousMethodCalls(no de); final Set<ASTMethodCallExpression> prevCalls = getPreviousMethodCalls(no de);
for (ASTMethodCallExpression prevCall : prevCalls) { for (ASTMethodCallExpression prevCall : prevCalls) {
collectCRUDMethodLevelChecks(prevCall); collectCRUDMethodLevelChecks(prevCall);
} }
skipping to change at line 593 skipping to change at line 609
final ASTUserClass wrappingClass = node.getFirstParentOfType(ASTUserClas s.class); final ASTUserClass wrappingClass = node.getFirstParentOfType(ASTUserClas s.class);
if (wrappingClass != null && Helper.isTestMethodOrClass(wrappingClass) if (wrappingClass != null && Helper.isTestMethodOrClass(wrappingClass)
|| wrappingMethod != null && Helper.isTestMethodOrClass(wrappingMeth od)) { || wrappingMethod != null && Helper.isTestMethodOrClass(wrappingMeth od)) {
return; return;
} }
if (wrappingMethod != null) { if (wrappingMethod != null) {
returnType = getReturnType(wrappingMethod); returnType = getReturnType(wrappingMethod);
} }
boolean violationAdded = false;
final ASTVariableDeclaration variableDecl = node.getFirstParentOfType(AS TVariableDeclaration.class); final ASTVariableDeclaration variableDecl = node.getFirstParentOfType(AS TVariableDeclaration.class);
if (variableDecl != null) { if (variableDecl != null) {
String type = variableDecl.getType(); String type = variableDecl.getType();
type = getSimpleType(type); type = getSimpleType(type);
StringBuilder typeCheck = new StringBuilder().append(variableDecl.ge tDefiningType()) StringBuilder typeCheck = new StringBuilder().append(variableDecl.ge tDefiningType())
.append(":").append(type); .append(":").append(type);
if (typesFromSOQL.isEmpty()) { if (typesFromSOQL.isEmpty()) {
validateCRUDCheckPresent(node, data, ANY, typeCheck.toString()); violationAdded = validateCRUDCheckPresent(node, data, ANY, typeC heck.toString());
} else { } else {
for (String typeFromSOQL : typesFromSOQL) { for (String typeFromSOQL : typesFromSOQL) {
validateCRUDCheckPresent(node, data, ANY, typeFromSOQL); violationAdded |= validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
} }
} }
} }
// If the node's already in violation, we don't need to keep checking.
if (violationAdded) {
return;
}
final ASTAssignmentExpression assignment = node.getFirstParentOfType(AST AssignmentExpression.class); final ASTAssignmentExpression assignment = node.getFirstParentOfType(AST AssignmentExpression.class);
if (assignment != null) { if (assignment != null) {
final ASTVariableExpression variable = assignment.getFirstChildOfTyp e(ASTVariableExpression.class); final ASTVariableExpression variable = assignment.getFirstChildOfTyp e(ASTVariableExpression.class);
if (variable != null) { if (variable != null) {
String variableWithClass = Helper.getFQVariableName(variable); String variableWithClass = Helper.getFQVariableName(variable);
if (varToTypeMapping.containsKey(variableWithClass)) { if (varToTypeMapping.containsKey(variableWithClass)) {
String type = varToTypeMapping.get(variableWithClass); String type = varToTypeMapping.get(variableWithClass);
if (typesFromSOQL.isEmpty()) { if (typesFromSOQL.isEmpty()) {
validateCRUDCheckPresent(node, data, ANY, type); violationAdded = validateCRUDCheckPresent(node, data, AN Y, type);
} else { } else {
for (String typeFromSOQL : typesFromSOQL) { for (String typeFromSOQL : typesFromSOQL) {
validateCRUDCheckPresent(node, data, ANY, typeFromSO QL); violationAdded |= validateCRUDCheckPresent(node, dat a, ANY, typeFromSOQL);
} }
} }
} }
} }
} }
// If the node's already in violation, we don't need to keep checking.
if (violationAdded) {
return;
}
final ASTReturnStatement returnStatement = node.getFirstParentOfType(AST ReturnStatement.class); final ASTReturnStatement returnStatement = node.getFirstParentOfType(AST ReturnStatement.class);
if (returnStatement != null) { if (returnStatement != null) {
if (typesFromSOQL.isEmpty()) { if (typesFromSOQL.isEmpty()) {
validateCRUDCheckPresent(node, data, ANY, returnType); violationAdded = validateCRUDCheckPresent(node, data, ANY, retur nType);
} else { } else {
for (String typeFromSOQL : typesFromSOQL) { for (String typeFromSOQL : typesFromSOQL) {
validateCRUDCheckPresent(node, data, ANY, typeFromSOQL); violationAdded |= validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
} }
} }
} }
// If the node's already in violation, we don't need to keep checking.
if (violationAdded) {
return;
}
final ASTForEachStatement forEachStatement = node.getFirstParentOfType(A STForEachStatement.class); final ASTForEachStatement forEachStatement = node.getFirstParentOfType(A STForEachStatement.class);
if (forEachStatement != null) { if (forEachStatement != null) {
if (typesFromSOQL.isEmpty()) { if (typesFromSOQL.isEmpty()) {
final ASTVariableDeclaration variableDeclFor = forEachStatement. getFirstParentOfType(ASTVariableDeclaration.class); final ASTVariableDeclaration variableDeclFor = forEachStatement. getFirstParentOfType(ASTVariableDeclaration.class);
if (variableDeclFor != null) { if (variableDeclFor != null) {
String type = variableDeclFor.getType(); String type = variableDeclFor.getType();
type = getSimpleType(type); type = getSimpleType(type);
StringBuilder typeCheck = new StringBuilder().append(variabl eDeclFor.getDefiningType()) StringBuilder typeCheck = new StringBuilder().append(variabl eDeclFor.getDefiningType())
.append(":").append(type); .append(":").append(type);
 End of changes. 18 change blocks. 
15 lines changed or deleted 46 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)