AbstractMethodInjection.java

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

Mutations

36

1.1
Location : testParameters
Killed by : none
negated conditional → NO_COVERAGE

40

1.1
Location : lambda$testParameters$0
Killed by : none
replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testParameters$0 → NO_COVERAGE

41

1.1
Location : lambda$testParameters$1
Killed by : none
replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testParameters$1 → NO_COVERAGE

43

1.1
Location : testParameters
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE

2.2
Location : testParameters
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE

45

1.1
Location : testParameters
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE

55

1.1
Location : testParameters
Killed by : none
removed call to com/jsql/model/InjectionModel::setAnalysisReport → NO_COVERAGE

61

1.1
Location : testParameters
Killed by : none
negated conditional → NO_COVERAGE

62

1.1
Location : testParameters
Killed by : none
negated conditional → NO_COVERAGE

63

1.1
Location : testParameters
Killed by : none
negated conditional → NO_COVERAGE

65

1.1
Location : testParameters
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE

73

1.1
Location : testParameters
Killed by : none
negated conditional → NO_COVERAGE

74

1.1
Location : testParameters
Killed by : none
negated conditional → NO_COVERAGE

77

1.1
Location : testParameters
Killed by : none
negated conditional → NO_COVERAGE

82

1.1
Location : testParameters
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE

2.2
Location : testParameters
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testParameters → NO_COVERAGE

87

1.1
Location : lambda$checkParamWithStar$2
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : lambda$checkParamWithStar$2
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkParamWithStar$2 → NO_COVERAGE

3.3
Location : lambda$checkParamWithStar$2
Killed by : none
negated conditional → NO_COVERAGE

90

1.1
Location : checkParamWithStar
Killed by : none
negated conditional → NO_COVERAGE

93

1.1
Location : checkParamWithStar
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkParamWithStar → NO_COVERAGE

2.2
Location : checkParamWithStar
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkParamWithStar → NO_COVERAGE

104

1.1
Location : lambda$checkLastParam$3
Killed by : none
replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkLastParam$3 → NO_COVERAGE

105

1.1
Location : lambda$checkLastParam$4
Killed by : none
replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$checkLastParam$4 → NO_COVERAGE

107

1.1
Location : checkLastParam
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkLastParam → NO_COVERAGE

2.2
Location : checkLastParam
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkLastParam → NO_COVERAGE

125

1.1
Location : checkAllParams
Killed by : none
negated conditional → NO_COVERAGE

127

1.1
Location : checkAllParams
Killed by : none
negated conditional → NO_COVERAGE

128

1.1
Location : checkAllParams
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::checkAllParams → NO_COVERAGE

136

1.1
Location : checkAllParams
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::checkAllParams → NO_COVERAGE

151

1.1
Location : isParamInjectable
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : isParamInjectable
Killed by : none
negated conditional → NO_COVERAGE

157

1.1
Location : isParamInjectable
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE

2.2
Location : isParamInjectable
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::isParamInjectable → NO_COVERAGE

169

1.1
Location : lambda$testJsonlessParam$6
Killed by : none
replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$6 → NO_COVERAGE

170

1.1
Location : lambda$testJsonlessParam$7
Killed by : none
replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$7 → NO_COVERAGE

172

1.1
Location : lambda$testJsonlessParam$8
Killed by : none
replaced return value with null for com/jsql/model/injection/method/AbstractMethodInjection::lambda$testJsonlessParam$8 → NO_COVERAGE

191

1.1
Location : testJsonlessParam
Killed by : none
negated conditional → NO_COVERAGE

194

1.1
Location : testJsonlessParam
Killed by : none
removed call to java/util/List::forEach → NO_COVERAGE

204

1.1
Location : testJsonlessParam
Killed by : none
replaced boolean return with true for com/jsql/model/injection/method/AbstractMethodInjection::testJsonlessParam → NO_COVERAGE

2.2
Location : testJsonlessParam
Killed by : none
replaced boolean return with false for com/jsql/model/injection/method/AbstractMethodInjection::testJsonlessParam → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.22.1