1 package com.jsql.util;
2
3 import com.jsql.model.InjectionModel;
4 import com.jsql.model.exception.JSqlException;
5 import com.jsql.model.injection.method.AbstractMethodInjection;
6 import org.apache.commons.lang3.StringUtils;
7 import org.apache.logging.log4j.LogManager;
8 import org.apache.logging.log4j.Logger;
9 import org.w3c.dom.Document;
10 import org.w3c.dom.Node;
11 import org.w3c.dom.Text;
12 import org.xml.sax.InputSource;
13 import org.xml.sax.SAXException;
14
15 import javax.xml.XMLConstants;
16 import javax.xml.parsers.DocumentBuilderFactory;
17 import javax.xml.parsers.ParserConfigurationException;
18 import javax.xml.transform.TransformerException;
19 import javax.xml.transform.TransformerFactory;
20 import javax.xml.transform.dom.DOMSource;
21 import javax.xml.transform.stream.StreamResult;
22 import java.io.IOException;
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.util.regex.Pattern;
26
27 public class SoapUtil {
28
29 private static final Logger LOGGER = LogManager.getRootLogger();
30
31 private final InjectionModel injectionModel;
32
33 public SoapUtil(InjectionModel injectionModel) {
34 this.injectionModel = injectionModel;
35 }
36
37 public boolean testParameters(boolean hasFoundInjection) {
38 if (!hasFoundInjection) {
39 LOGGER.log(
40 LogLevelUtil.CONSOLE_DEFAULT,
41 "{} [SOAP] params...",
42 () -> I18nUtil.valueByKey(AbstractMethodInjection.LOG_CHECKING)
43 );
44 } else {
45 return true;
46 }
47
48 if (
49 this.injectionModel.getMediatorUtils().preferencesUtil().isCheckingAllSoapParam()
50 && this.injectionModel.getMediatorUtils().parameterUtil().isRequestSoap()
51 ) {
52 try {
53 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Parsing SOAP request...");
54 if (this.injectionModel.getMediatorUtils().parameterUtil().getRawRequest().contains(InjectionModel.STAR)) {
55 return this.injectionModel.getMediatorMethod().getRequest().testParameters();
56 } else {
57 var document = SoapUtil.convertToDocument(this.injectionModel.getMediatorUtils().parameterUtil().getRawRequest());
58 return this.isTextNodeInjectable(document, document.getDocumentElement());
59 }
60 } catch (ParserConfigurationException | IOException | SAXException e) {
61 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Incorrect SOAP template: {}", e.getMessage());
62 } catch (JSqlException e) {
63 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "No SOAP Request injection");
64 }
65 }
66 return false;
67 }
68
69 public static Document convertToDocument(String xmlStr) throws ParserConfigurationException, SAXException, IOException {
70 var factory = DocumentBuilderFactory.newInstance();
71 factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, StringUtils.EMPTY);
72 factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, StringUtils.EMPTY);
73 factory.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
74 factory.setExpandEntityReferences(false);
75 var builder = factory.newDocumentBuilder();
76 return builder.parse(new InputSource(new StringReader(xmlStr)));
77 }
78
79 public boolean isTextNodeInjectable(Document originDocument, Node node) {
80 var nodeList = node.getChildNodes();
81 if (nodeList.getLength() == 0) {
82 try {
83 var documentBuilderFactory = DocumentBuilderFactory.newInstance();
84 var document = documentBuilderFactory.newDocumentBuilder().newDocument();
85 Text textNode = document.createTextNode(StringUtils.EMPTY);
86 Node nodeWithText = originDocument.importNode(textNode, true);
87 node.appendChild(nodeWithText);
88 } catch (ParserConfigurationException e) {
89 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
90 }
91 }
92 for (var i = 0 ; i < nodeList.getLength() ; i++) {
93 var currentNode = nodeList.item(i);
94 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
95 if (this.isTextNodeInjectable(originDocument, currentNode)) {
96 return true;
97 }
98 } else {
99 SoapUtil.removeInjectionPoint(originDocument, originDocument.getDocumentElement());
100 var origin = currentNode.getTextContent();
101 currentNode.setTextContent(InjectionModel.STAR);
102 this.injectionModel.getMediatorUtils().parameterUtil().initRequest(SoapUtil.convertDocumentToString(originDocument));
103
104 try {
105 LOGGER.log(
106 LogLevelUtil.CONSOLE_INFORM,
107 "{} [SOAP] {}={}",
108 () -> I18nUtil.valueByKey(AbstractMethodInjection.LOG_CHECKING),
109 () -> currentNode.getParentNode().getNodeName(),
110 () -> currentNode.getTextContent().replace(InjectionModel.STAR, StringUtils.EMPTY)
111 );
112 if (this.injectionModel.getMediatorMethod().getRequest().testParameters()) {
113 return true;
114 }
115 currentNode.setTextContent(origin);
116 } catch (JSqlException e) {
117 LOGGER.log(
118 LogLevelUtil.CONSOLE_ERROR,
119 String.format(
120 "No SOAP Request injection for %s=%s",
121 currentNode.getParentNode().getNodeName(),
122 currentNode.getTextContent().replace(InjectionModel.STAR, StringUtils.EMPTY)
123 )
124 );
125 }
126 }
127 }
128 return false;
129 }
130
131 public static void removeInjectionPoint(Document doc, Node node) {
132 var nodeList = node.getChildNodes();
133 for (var i = 0 ; i < nodeList.getLength() ; i++) {
134 var currentNode = nodeList.item(i);
135 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
136 SoapUtil.removeInjectionPoint(doc, currentNode);
137 } else if (currentNode.getNodeType() == Node.TEXT_NODE) {
138 currentNode.setTextContent(
139 currentNode
140 .getTextContent()
141 .replaceAll(Pattern.quote(InjectionModel.STAR) + "*$", StringUtils.EMPTY)
142 );
143 }
144 }
145 }
146
147 private static String convertDocumentToString(Document doc) {
148 var transformerFactory = TransformerFactory.newInstance();
149 transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, StringUtils.EMPTY);
150 transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, StringUtils.EMPTY);
151
152 String output = null;
153 try {
154 var transformer = transformerFactory.newTransformer();
155 var writer = new StringWriter();
156 transformer.transform(new DOMSource(doc), new StreamResult(writer));
157 output = writer.getBuffer().toString();
158 } catch (TransformerException e) {
159
160 }
161 return output;
162 }
163 }