View Javadoc
1   package com.jsql.util;
2   
3   import com.jsql.model.InjectionModel;
4   import com.jsql.model.exception.JSqlException;
5   import org.apache.commons.lang3.StringUtils;
6   import org.apache.logging.log4j.LogManager;
7   import org.apache.logging.log4j.Logger;
8   import org.w3c.dom.Document;
9   import org.w3c.dom.Node;
10  import org.xml.sax.InputSource;
11  import org.xml.sax.SAXException;
12  
13  import javax.xml.XMLConstants;
14  import javax.xml.parsers.DocumentBuilderFactory;
15  import javax.xml.parsers.ParserConfigurationException;
16  import javax.xml.transform.TransformerException;
17  import javax.xml.transform.TransformerFactory;
18  import javax.xml.transform.dom.DOMSource;
19  import javax.xml.transform.stream.StreamResult;
20  import java.io.IOException;
21  import java.io.StringReader;
22  import java.io.StringWriter;
23  import java.util.regex.Pattern;
24  
25  public class SoapUtil {
26      
27      /**
28       * Log4j logger sent to view.
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(LogLevelUtil.CONSOLE_DEFAULT, "{} SOAP...", () -> I18nUtil.valueByKey("LOG_CHECKING"));
41          } else {
42              return true;
43          }
44  
45          if (
46              this.injectionModel.getMediatorUtils().getPreferencesUtil().isCheckingAllSoapParam()
47              && this.injectionModel.getMediatorUtils().getParameterUtil().isRequestSoap()
48          ) {
49              try {
50                  var doc = SoapUtil.convertToDocument(this.injectionModel.getMediatorUtils().getParameterUtil().getRawRequest());
51                  LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Parsing SOAP from Request...");
52                  return this.isTextNodeInjectable(doc, doc.getDocumentElement());
53              } catch (Exception e) {
54                  LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "SOAP not detected");
55              }
56          }
57          return false;
58      }
59      
60      public static Document convertToDocument(String xmlStr) throws ParserConfigurationException, SAXException, IOException {
61          var factory = DocumentBuilderFactory.newInstance();
62          factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, StringUtils.EMPTY);
63          factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, StringUtils.EMPTY);
64          factory.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
65          factory.setExpandEntityReferences(false);
66          var builder = factory.newDocumentBuilder();
67          return builder.parse(new InputSource(new StringReader(xmlStr)));
68      }
69  
70      public boolean isTextNodeInjectable(Document doc, Node node) {
71          var nodeList = node.getChildNodes();
72          for (var i = 0; i < nodeList.getLength(); i++) {
73              var currentNode = nodeList.item(i);
74              if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
75                  if (this.isTextNodeInjectable(doc, currentNode)) {  // calls this method for all the children which is Element
76                      return true;
77                  }
78              } else if (currentNode.getNodeType() == Node.TEXT_NODE) {
79                  
80                  SoapUtil.removeInjectionPoint(doc, doc.getDocumentElement());
81                  currentNode.setTextContent(currentNode.getTextContent().replace(InjectionModel.STAR, StringUtils.EMPTY) + InjectionModel.STAR);
82                  this.injectionModel.getMediatorUtils().getParameterUtil().initRequest(SoapUtil.convertDocumentToString(doc));
83                  
84                  try {
85                      LOGGER.log(
86                          LogLevelUtil.CONSOLE_INFORM,
87                          "{} SOAP {}={}",
88                          () -> I18nUtil.valueByKey("LOG_CHECKING"),
89                          () -> currentNode.getParentNode().getNodeName(),
90                          () -> currentNode.getTextContent().replace(InjectionModel.STAR, StringUtils.EMPTY)
91                      );
92                      if (this.injectionModel.getMediatorMethod().getRequest().testParameters()) {
93                          return true;
94                      }
95                  } catch (JSqlException e) {
96                      // Injection failure
97                      LOGGER.log(
98                          LogLevelUtil.CONSOLE_ERROR,
99                          String.format(
100                             "No SOAP Request injection for %s=%s",
101                             currentNode.getParentNode().getNodeName(),
102                             currentNode.getTextContent().replace(InjectionModel.STAR, StringUtils.EMPTY)
103                         )
104                     );
105                 }
106             }
107         }
108         return false;
109     }
110 
111     public static void removeInjectionPoint(Document doc, Node node) {
112         var nodeList = node.getChildNodes();
113         for (var i = 0; i < nodeList.getLength(); i++) {
114             var currentNode = nodeList.item(i);
115             if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
116                 SoapUtil.removeInjectionPoint(doc, currentNode);  // calls this method for all the children which is Element
117             } else if (currentNode.getNodeType() == Node.TEXT_NODE) {
118                 currentNode.setTextContent(
119                     currentNode
120                     .getTextContent()
121                     .replaceAll(Pattern.quote(InjectionModel.STAR) + "*$", StringUtils.EMPTY)
122                 );
123             }
124         }
125     }
126     
127     private static String convertDocumentToString(Document doc) {
128         var transformerFactory = TransformerFactory.newInstance();
129         transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, StringUtils.EMPTY);
130         transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, StringUtils.EMPTY);
131         
132         String output = null;
133         try {
134             var transformer = transformerFactory.newTransformer();
135             var writer = new StringWriter();
136             transformer.transform(new DOMSource(doc), new StreamResult(writer));
137             output = writer.getBuffer().toString();
138         } catch (TransformerException e) {
139             // ignore
140         }
141         return output;
142     }
143 }