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