| 1 | package com.jsql.model.injection.method; | |
| 2 | ||
| 3 | import com.jsql.model.InjectionModel; | |
| 4 | import com.jsql.model.exception.JSqlException; | |
| 5 | import com.jsql.model.exception.StoppedByUserSlidingException; | |
| 6 | import com.jsql.util.I18nUtil; | |
| 7 | import com.jsql.util.JsonUtil; | |
| 8 | import com.jsql.util.LogLevelUtil; | |
| 9 | import org.apache.commons.lang3.StringUtils; | |
| 10 | import org.apache.logging.log4j.LogManager; | |
| 11 | import org.apache.logging.log4j.Logger; | |
| 12 | import org.json.JSONException; | |
| 13 | ||
| 14 | import java.io.Serializable; | |
| 15 | import java.util.AbstractMap.SimpleEntry; | |
| 16 | import java.util.List; | |
| 17 | import java.util.regex.Pattern; | |
| 18 | ||
| 19 | public abstract class AbstractMethodInjection implements Serializable { | |
| 20 | | |
| 21 | private static final Logger LOGGER = LogManager.getRootLogger(); | |
| 22 | | |
| 23 | protected final InjectionModel injectionModel; | |
| 24 | | |
| 25 | protected AbstractMethodInjection(InjectionModel injectionModel) { | |
| 26 | this.injectionModel = injectionModel; | |
| 27 | } | |
| 28 | | |
| 29 | public abstract boolean isCheckingAllParam(); | |
| 30 | public abstract String getParamsAsString(); | |
| 31 | public abstract List<SimpleEntry<String, String>> getParams(); | |
| 32 | public abstract String name(); | |
| 33 | | |
| 34 | public boolean testParameters(boolean hasFoundInjection) throws JSqlException { | |
| 35 |
1
1. testParameters : negated conditional → NO_COVERAGE |
if (!hasFoundInjection) { |
| 36 | LOGGER.log( | |
| 37 | LogLevelUtil.CONSOLE_DEFAULT, | |
| 38 | "{} {} params...", | |
| 39 |
1
1. lambda$testParameters$0 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testParameters$0 → NO_COVERAGE |
() -> I18nUtil.valueByKey("LOG_CHECKING"), |
| 40 |
1
1. lambda$testParameters$1 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testParameters$1 → NO_COVERAGE |
() -> this.name().toLowerCase() |
| 41 | ); | |
| 42 |
2
1. testParameters : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE 2. testParameters : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return this.testParameters(); |
| 43 | } | |
| 44 |
1
1. testParameters : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return true; |
| 45 | } | |
| 46 | ||
| 47 | /** | |
| 48 | * Verify if injection works for specific Method using 3 modes: standard (last param), injection point | |
| 49 | * and full params injection. Special injections like JSON and SOAP are checked. | |
| 50 | * @return true if injection didn't fail | |
| 51 | * @throws JSqlException when no params integrity, process stopped by user, or injection failure | |
| 52 | */ | |
| 53 | public boolean testParameters() throws JSqlException { | |
| 54 | var hasFoundInjection = false; | |
| 55 | | |
| 56 | // Injects URL, Request or Header params only if user tests every params | |
| 57 | // or method is selected by user. | |
| 58 | if ( | |
| 59 |
1
1. testParameters : negated conditional → NO_COVERAGE |
!this.injectionModel.getMediatorUtils().getPreferencesUtil().isCheckingAllParam() |
| 60 |
1
1. testParameters : negated conditional → NO_COVERAGE |
&& this.injectionModel.getMediatorUtils().getConnectionUtil().getMethodInjection() != this |
| 61 | ) { | |
| 62 |
1
1. testParameters : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return false; |
| 63 | } | |
| 64 | | |
| 65 | // Force injection method of model to current running method | |
| 66 |
1
1. testParameters : removed call to com/jsql/util/ConnectionUtil::setMethodInjection → NO_COVERAGE |
this.injectionModel.getMediatorUtils().getConnectionUtil().setMethodInjection(this); |
| 67 | | |
| 68 | // Injection by injection point in params or in path | |
| 69 | if ( | |
| 70 |
1
1. testParameters : negated conditional → NO_COVERAGE |
this.getParamsAsString().contains(InjectionModel.STAR) |
| 71 |
1
1. testParameters : negated conditional → NO_COVERAGE |
|| this.injectionModel.getMediatorUtils().getConnectionUtil().getUrlBase().contains(InjectionModel.STAR) |
| 72 | ) { | |
| 73 | hasFoundInjection = this.checkParamWithStar(); | |
| 74 |
1
1. testParameters : negated conditional → NO_COVERAGE |
} else if (!this.isCheckingAllParam()) { |
| 75 | hasFoundInjection = this.checkLastParam(); | |
| 76 | } else { | |
| 77 | hasFoundInjection = this.checkAllParams(); | |
| 78 | } | |
| 79 |
2
1. testParameters : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE 2. testParameters : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE |
return hasFoundInjection; |
| 80 | } | |
| 81 | ||
| 82 | private boolean checkParamWithStar() throws JSqlException { | |
| 83 | SimpleEntry<String, String> parameterToInject = this.getParams().stream() | |
| 84 |
2
1. lambda$checkParamWithStar$2 : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkParamWithStar$2 → NO_COVERAGE 2. lambda$checkParamWithStar$2 : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkParamWithStar$2 → NO_COVERAGE |
.filter(entry -> entry.getValue().contains("*")) |
| 85 | .findFirst() | |
| 86 | .orElse(null); | |
| 87 |
2
1. checkParamWithStar : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkParamWithStar → NO_COVERAGE 2. checkParamWithStar : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkParamWithStar → NO_COVERAGE |
return this.injectionModel.getMediatorStrategy().testStrategies(parameterToInject); |
| 88 | } | |
| 89 | ||
| 90 | /** | |
| 91 | * Default injection: last param tested only | |
| 92 | */ | |
| 93 | private boolean checkLastParam() throws JSqlException { | |
| 94 | // Will check param value by user. | |
| 95 | // Notice options 'Inject each URL params' and 'inject JSON' must be checked both | |
| 96 | // for JSON injection of last param | |
| 97 | SimpleEntry<String, String> parameterToInject = this.getParams().stream() | |
| 98 |
1
1. lambda$checkLastParam$3 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkLastParam$3 → NO_COVERAGE |
.reduce((a, b) -> b) |
| 99 |
1
1. lambda$checkLastParam$4 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkLastParam$4 → NO_COVERAGE |
.orElseThrow(() -> new JSqlException("Missing last parameter")); |
| 100 |
2
1. checkLastParam : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkLastParam → NO_COVERAGE 2. checkLastParam : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkLastParam → NO_COVERAGE |
return this.injectionModel.getMediatorStrategy().testStrategies(parameterToInject); |
| 101 | } | |
| 102 | ||
| 103 | /** | |
| 104 | * Injection of every params: isCheckingAllParam() == true. | |
| 105 | * Params are tested one by one in two loops: | |
| 106 | * - inner loop erases * from previous param | |
| 107 | * - outer loop adds * to current param | |
| 108 | */ | |
| 109 | private boolean checkAllParams() throws StoppedByUserSlidingException { | |
| 110 | // This param will be marked by * if injection is found, | |
| 111 | // inner loop will erase mark * otherwise | |
| 112 | for (SimpleEntry<String, String> paramBase: this.getParams()) { | |
| 113 | // This param is the current tested one. | |
| 114 | // For JSON value attributes are traversed one by one to test every value. | |
| 115 | // For standard value mark * is simply added to the end of its value. | |
| 116 | for (SimpleEntry<String, String> paramStar: this.getParams()) { | |
| 117 |
1
1. checkAllParams : negated conditional → NO_COVERAGE |
if (paramStar == paramBase) { |
| 118 | try { | |
| 119 |
1
1. checkAllParams : negated conditional → NO_COVERAGE |
if (this.isParamInjectable(paramStar)) { |
| 120 |
1
1. checkAllParams : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkAllParams → NO_COVERAGE |
return true; |
| 121 | } | |
| 122 | } catch (JSONException e) { | |
| 123 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
| 124 | } | |
| 125 | } | |
| 126 | } | |
| 127 | } | |
| 128 |
1
1. checkAllParams : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkAllParams → NO_COVERAGE |
return false; |
| 129 | } | |
| 130 | ||
| 131 | private boolean isParamInjectable(SimpleEntry<String, String> paramStar) throws StoppedByUserSlidingException { | |
| 132 | boolean hasFoundInjection; | |
| 133 | | |
| 134 | // Will test if current value is a JSON entity | |
| 135 | Object jsonEntity = JsonUtil.getJson(paramStar.getValue()); | |
| 136 | | |
| 137 | // Define a tree of JSON attributes with path as the key: root.a => value of a | |
| 138 | List<SimpleEntry<String, String>> attributesJson = JsonUtil.createEntries(jsonEntity, "root", null); | |
| 139 | | |
| 140 | // When option 'Inject JSON' is selected and there's a JSON entity to inject | |
| 141 | // then loop through each path to add * at the end of value and test each strategy. | |
| 142 | // Marks * are erased between each test. | |
| 143 |
2
1. isParamInjectable : negated conditional → NO_COVERAGE 2. isParamInjectable : negated conditional → NO_COVERAGE |
if (!attributesJson.isEmpty() && this.injectionModel.getMediatorUtils().getPreferencesUtil().isCheckingAllJsonParam()) { |
| 144 | hasFoundInjection = this.injectionModel.getMediatorUtils().getJsonUtil().testJsonParam(this, paramStar); | |
| 145 | } else { | |
| 146 | hasFoundInjection = this.testJsonlessParam(paramStar); // Standard non JSON injection | |
| 147 | } | |
| 148 |
2
1. isParamInjectable : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE 2. isParamInjectable : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE |
return hasFoundInjection; |
| 149 | } | |
| 150 | | |
| 151 | public boolean testJsonlessParam(SimpleEntry<String, String> paramStar) throws StoppedByUserSlidingException { | |
| 152 | var hasFoundInjection = false; | |
| 153 | ||
| 154 | paramStar.setValue(paramStar.getValue() + InjectionModel.STAR); | |
| 155 | | |
| 156 | try { | |
| 157 | LOGGER.log( | |
| 158 | LogLevelUtil.CONSOLE_INFORM, | |
| 159 | "{} {} parameter {}={}", | |
| 160 |
1
1. lambda$testJsonlessParam$5 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$5 → NO_COVERAGE |
() -> I18nUtil.valueByKey("LOG_CHECKING"), |
| 161 | this::name, | |
| 162 | paramStar::getKey, | |
| 163 |
1
1. lambda$testJsonlessParam$6 : replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$6 → NO_COVERAGE |
() -> paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY) |
| 164 | ); | |
| 165 | | |
| 166 | // Test current standard value marked with * for injection | |
| 167 | // Keep original param | |
| 168 | hasFoundInjection = this.injectionModel.getMediatorStrategy().testStrategies(paramStar); | |
| 169 | | |
| 170 | } catch (StoppedByUserSlidingException e) { // Break all params processing in upper methods | |
| 171 | throw e; | |
| 172 | } catch (JSqlException e) { // Injection failure | |
| 173 | LOGGER.log( | |
| 174 | LogLevelUtil.CONSOLE_ERROR, | |
| 175 | "No {} injection found for parameter {}={} ({})", | |
| 176 | this.name(), | |
| 177 | paramStar.getKey(), | |
| 178 | paramStar.getValue().replaceAll("\\+.?$|\\" + InjectionModel.STAR, StringUtils.EMPTY), | |
| 179 | e.getMessage() | |
| 180 | ); | |
| 181 | } finally { | |
| 182 |
1
1. testJsonlessParam : negated conditional → NO_COVERAGE |
if (!hasFoundInjection) { // Erase * from JSON if failure |
| 183 | | |
| 184 | // Erase * at the end of each params | |
| 185 |
1
1. testJsonlessParam : removed call to java/util/List::forEach → NO_COVERAGE |
this.getParams().forEach(e -> |
| 186 | e.setValue( | |
| 187 | e.getValue().replaceAll(Pattern.quote(InjectionModel.STAR) +"$", StringUtils.EMPTY) | |
| 188 | ) | |
| 189 | ); | |
| 190 | | |
| 191 | // TODO It erases STAR from value => * can't be used in parameter | |
| 192 | paramStar.setValue(paramStar.getValue().replace(InjectionModel.STAR, StringUtils.EMPTY)); | |
| 193 | } | |
| 194 | } | |
| 195 |
2
1. testJsonlessParam : replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testJsonlessParam → NO_COVERAGE 2. testJsonlessParam : replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testJsonlessParam → NO_COVERAGE |
return hasFoundInjection; |
| 196 | } | |
| 197 | } | |
Mutations | ||
| 35 |
1.1 |
|
| 39 |
1.1 |
|
| 40 |
1.1 |
|
| 42 |
1.1 2.2 |
|
| 44 |
1.1 |
|
| 59 |
1.1 |
|
| 60 |
1.1 |
|
| 62 |
1.1 |
|
| 66 |
1.1 |
|
| 70 |
1.1 |
|
| 71 |
1.1 |
|
| 74 |
1.1 |
|
| 79 |
1.1 2.2 |
|
| 84 |
1.1 2.2 |
|
| 87 |
1.1 2.2 |
|
| 98 |
1.1 |
|
| 99 |
1.1 |
|
| 100 |
1.1 2.2 |
|
| 117 |
1.1 |
|
| 119 |
1.1 |
|
| 120 |
1.1 |
|
| 128 |
1.1 |
|
| 143 |
1.1 2.2 |
|
| 148 |
1.1 2.2 |
|
| 160 |
1.1 |
|
| 163 |
1.1 |
|
| 182 |
1.1 |
|
| 185 |
1.1 |
|
| 195 |
1.1 2.2 |