1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package xpath;
  25 
  26 import java.io.FilePermission;
  27 import java.io.IOException;
  28 import java.io.InputStream;
  29 import java.util.Iterator;
  30 import java.util.List;
  31 
  32 import javax.xml.XMLConstants;
  33 import javax.xml.namespace.NamespaceContext;
  34 import javax.xml.namespace.QName;
  35 import javax.xml.parsers.DocumentBuilder;
  36 import javax.xml.parsers.DocumentBuilderFactory;
  37 import javax.xml.parsers.ParserConfigurationException;
  38 import javax.xml.xpath.XPath;
  39 import javax.xml.xpath.XPathExpressionException;
  40 import javax.xml.xpath.XPathFactory;
  41 import javax.xml.xpath.XPathFactoryConfigurationException;
  42 import javax.xml.xpath.XPathFunction;
  43 import javax.xml.xpath.XPathFunctionException;
  44 import javax.xml.xpath.XPathFunctionResolver;
  45 
  46 import jaxp.library.JAXPTestUtilities;
  47 
  48 import org.testng.Assert;
  49 import org.testng.annotations.Test;
  50 import org.w3c.dom.Document;
  51 import org.xml.sax.SAXException;
  52 
  53 /*
  54  * @summary Test when FEATURE_SECURE_PROCESSING is true, calling an external function will cause XPathFunctionException.
  55  */
  56 @Test(singleThreaded = true)
  57 public class SecureProcessingTest {
  58     public void runWithSecurityManager() throws Exception {
  59         JAXPTestUtilities.tryRunWithPolicyManager(() -> testSecureProcessing(),
  60                 new FilePermission(System.getProperty("test.src") + "/-", "read"));
  61     }
  62 
  63     public void runWithoutSecurityManager() throws Exception {
  64         testSecureProcessing();
  65     }
  66 
  67     private final void testSecureProcessing() {
  68         boolean _isSecureMode = System.getSecurityManager() != null;
  69 
  70         final String XPATH_EXPRESSION = "ext:helloWorld()";
  71 
  72         // the xml source
  73         InputStream xmlStream = this.getClass().getResourceAsStream("SecureProcessingTest.xml");
  74 
  75         DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  76         DocumentBuilder documentBuilder = null;
  77         Document document = null;
  78 
  79         try {
  80             documentBuilder = documentBuilderFactory.newDocumentBuilder();
  81             document = documentBuilder.parse(xmlStream);
  82         } catch (ParserConfigurationException parserConfigurationException) {
  83             parserConfigurationException.printStackTrace();
  84             Assert.fail(parserConfigurationException.toString());
  85         } catch (SAXException saxException) {
  86             saxException.printStackTrace();
  87             Assert.fail(saxException.toString());
  88         } catch (IOException ioException) {
  89             ioException.printStackTrace();
  90             Assert.fail(ioException.toString());
  91         }
  92 
  93         // the XPath
  94         XPathFactory xPathFactory = null;
  95         XPath xPath = null;
  96         String xPathResult = null;
  97 
  98         // SECURE_PROCESSING == false
  99         // evaluate an expression with a user defined function with a non-secure
 100         // XPath
 101         // expect success
 102         if (!_isSecureMode) { // jaxp secure feature can not be turned off when
 103                               // security manager is present
 104             try {
 105                 xPathFactory = xPathFactory.newInstance();
 106                 xPathFactory.setXPathFunctionResolver(new MyXPathFunctionResolver());
 107                 xPathFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 108 
 109                 xPath = xPathFactory.newXPath();
 110                 xPath.setNamespaceContext(new MyNamespaceContext());
 111 
 112                 xPathResult = xPath.evaluate(XPATH_EXPRESSION, document);
 113             } catch (XPathFactoryConfigurationException xPathFactoryConfigurationException) {
 114                 xPathFactoryConfigurationException.printStackTrace();
 115                 Assert.fail(xPathFactoryConfigurationException.toString());
 116             } catch (XPathExpressionException xPathExpressionException) {
 117                 xPathExpressionException.printStackTrace();
 118                 Assert.fail(xPathExpressionException.toString());
 119             }
 120 
 121             // expected success
 122             System.out.println("XPath result (SECURE_PROCESSING == false) = \"" + xPathResult + "\"");
 123         }
 124         // now try with SECURE_PROCESSING == true
 125         // evaluate an expression with a user defined function with a secure
 126         // XPath
 127         // expect Exception
 128         boolean securityException = false;
 129         try {
 130             xPathFactory = xPathFactory.newInstance();
 131             xPathFactory.setXPathFunctionResolver(new MyXPathFunctionResolver());
 132             xPathFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
 133 
 134             xPath = xPathFactory.newXPath();
 135             xPath.setNamespaceContext(new MyNamespaceContext());
 136 
 137             xPathResult = xPath.evaluate(XPATH_EXPRESSION, document);
 138         } catch (XPathFactoryConfigurationException xPathFactoryConfigurationException) {
 139             xPathFactoryConfigurationException.printStackTrace();
 140             Assert.fail(xPathFactoryConfigurationException.toString());
 141         } catch (XPathFunctionException xPathFunctionException) {
 142             // expected security exception
 143             securityException = true;
 144             xPathFunctionException.printStackTrace(System.out);
 145         } catch (XPathExpressionException xPathExpressionException) {
 146             xPathExpressionException.printStackTrace();
 147             Assert.fail(xPathExpressionException.toString());
 148         }
 149 
 150         // expected Exception
 151         if (!securityException) {
 152             Assert.fail("XPath result (SECURE_PROCESSING == true) = \"" + xPathResult + "\"");
 153         }
 154     }
 155 
 156     private class MyXPathFunctionResolver implements XPathFunctionResolver {
 157 
 158         public XPathFunction resolveFunction(QName functionName, int arity) {
 159 
 160             // not a real ewsolver, always return a default XPathFunction
 161             return new MyXPathFunction();
 162         }
 163     }
 164 
 165     private class MyXPathFunction implements XPathFunction {
 166 
 167         public Object evaluate(List list) throws XPathFunctionException {
 168 
 169             return "Hello World";
 170         }
 171     }
 172 
 173     private class MyNamespaceContext implements NamespaceContext {
 174 
 175         public String getNamespaceURI(String prefix) {
 176             if (prefix == null) {
 177                 throw new IllegalArgumentException("The prefix cannot be null.");
 178             }
 179 
 180             if (prefix.equals("ext")) {
 181                 return "http://ext.com";
 182             } else {
 183                 return null;
 184             }
 185         }
 186 
 187         public String getPrefix(String namespace) {
 188 
 189             if (namespace == null) {
 190                 throw new IllegalArgumentException("The namespace uri cannot be null.");
 191             }
 192 
 193             if (namespace.equals("http://ext.com")) {
 194                 return "ext";
 195             } else {
 196                 return null;
 197             }
 198         }
 199 
 200         public Iterator getPrefixes(String namespace) {
 201             return null;
 202         }
 203     }
 204 }