1 /*
   2  * Copyright (c) 2013, 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  * @test
  25  * @bug 8004476
  26  * @summary test XPath extension functions
  27  * @run main/othervm XPathExFuncTest
  28  */
  29 import java.io.FileInputStream;
  30 import java.io.InputStream;
  31 import java.security.AllPermission;
  32 import java.security.CodeSource;
  33 import java.security.Permission;
  34 import java.security.PermissionCollection;
  35 import java.security.Permissions;
  36 import java.security.Policy;
  37 import java.security.ProtectionDomain;
  38 import java.util.Iterator;
  39 import java.util.List;
  40 import javax.xml.XMLConstants;
  41 import javax.xml.namespace.NamespaceContext;
  42 import javax.xml.namespace.QName;
  43 import javax.xml.parsers.DocumentBuilder;
  44 import javax.xml.parsers.DocumentBuilderFactory;
  45 import javax.xml.xpath.XPath;
  46 import javax.xml.xpath.XPathExpressionException;
  47 import javax.xml.xpath.XPathFactory;
  48 import javax.xml.xpath.XPathFactoryConfigurationException;
  49 import javax.xml.xpath.XPathFunction;
  50 import javax.xml.xpath.XPathFunctionException;
  51 import javax.xml.xpath.XPathFunctionResolver;
  52 import org.w3c.dom.Document;
  53 
  54 /**
  55  * test XPath extension functions
  56  *
  57  * @author huizhe.wang@oracle.com
  58  */
  59 public class XPathExFuncTest extends TestBase {
  60 
  61     final static String ENABLE_EXTENSION_FUNCTIONS = "http://www.oracle.com/xml/jaxp/properties/enableExtensionFunctions";
  62     final static String CLASSNAME = "DocumentBuilderFactoryImpl";
  63     final String XPATH_EXPRESSION = "ext:helloWorld()";
  64 
  65     /**
  66      * Creates a new instance of StreamReader
  67      */
  68     public XPathExFuncTest(String name) {
  69         super(name);
  70     }
  71     boolean hasSM;
  72     String xslFile, xslFileId;
  73     String xmlFile, xmlFileId;
  74 
  75     protected void setUp() {
  76         super.setUp();
  77         xmlFile = filepath + "/SecureProcessingTest.xml";
  78 
  79     }
  80 
  81     /**
  82      * @param args the command line arguments
  83      */
  84     public static void main(String[] args) {
  85         XPathExFuncTest test = new XPathExFuncTest("OneTest");
  86         test.setUp();
  87 
  88         test.testExtFunc();
  89         test.testExtFuncNotAllowed();
  90         test.testEnableExtFunc();
  91         test.tearDown();
  92 
  93     }
  94 
  95     /**
  96      * by default, extension function is enabled
  97      */
  98     public void testExtFunc() {
  99 
 100         try {
 101             evaluate(false);
 102             System.out.println("testExtFunc: OK");
 103         } catch (XPathFactoryConfigurationException e) {
 104             fail(e.getMessage());
 105         } catch (XPathExpressionException e) {
 106             fail(e.getMessage());
 107         }
 108     }
 109 
 110     /**
 111      * Security is enabled, extension function not allowed
 112      */
 113     public void testExtFuncNotAllowed() {
 114         Policy p = new SimplePolicy(new AllPermission());
 115         Policy.setPolicy(p);
 116         System.setSecurityManager(new SecurityManager());
 117 
 118         try {
 119             evaluate(false);
 120         } catch (XPathFactoryConfigurationException e) {
 121             fail(e.getMessage());
 122         } catch (XPathExpressionException ex) {
 123             //expected since extension function is disallowed
 124             System.out.println("testExtFuncNotAllowed: OK");
 125         } finally {
 126             System.setSecurityManager(null);
 127         }
 128     }
 129 
 130     /**
 131      * Security is enabled, use new feature: enableExtensionFunctions
 132      */
 133     public void testEnableExtFunc() {
 134         Policy p = new SimplePolicy(new AllPermission());
 135         Policy.setPolicy(p);
 136         System.setSecurityManager(new SecurityManager());
 137 
 138 
 139         try {
 140             evaluate(true);
 141             System.out.println("testEnableExt: OK");
 142         } catch (XPathFactoryConfigurationException e) {
 143             fail(e.getMessage());
 144         } catch (XPathExpressionException e) {
 145             fail(e.getMessage());
 146         } finally {
 147             System.setSecurityManager(null);
 148         }
 149     }
 150 
 151     Document getDocument() {
 152         // the xml source
 153         DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
 154         DocumentBuilder documentBuilder = null;
 155         Document document = null;
 156 
 157         try {
 158             documentBuilder = documentBuilderFactory.newDocumentBuilder();
 159             InputStream xmlStream = new FileInputStream(xmlFile);
 160             document = documentBuilder.parse(xmlStream);
 161         } catch (Exception e) {
 162             fail(e.toString());
 163         }
 164         return document;
 165     }
 166 
 167     void evaluate(boolean enableExt) throws XPathFactoryConfigurationException, XPathExpressionException {
 168         Document document = getDocument();
 169 
 170         XPathFactory xPathFactory = XPathFactory.newInstance();
 171         /**
 172          * Use of the extension function 'http://exslt.org/strings:tokenize' is
 173          * not allowed when the secure processing feature is set to true.
 174          * Attempt to use the new property to enable extension function
 175          */
 176         if (enableExt) {
 177             boolean isExtensionSupported = enableExtensionFunction(xPathFactory);
 178         }
 179 
 180         xPathFactory.setXPathFunctionResolver(new MyXPathFunctionResolver());
 181         if (System.getSecurityManager() == null) {
 182             xPathFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 183         }
 184 
 185         XPath xPath = xPathFactory.newXPath();
 186         xPath.setNamespaceContext(new MyNamespaceContext());
 187 
 188         String xPathResult = xPath.evaluate(XPATH_EXPRESSION, document);
 189         System.out.println(
 190                 "XPath result (enableExtensionFunction == " + enableExt + ") = \""
 191                 + xPathResult
 192                 + "\"");
 193     }
 194 
 195     public class MyXPathFunctionResolver
 196             implements XPathFunctionResolver {
 197 
 198         public XPathFunction resolveFunction(QName functionName, int arity) {
 199 
 200             // not a real ewsolver, always return a default XPathFunction
 201             return new MyXPathFunction();
 202         }
 203     }
 204 
 205     public class MyXPathFunction
 206             implements XPathFunction {
 207 
 208         public Object evaluate(List list) throws XPathFunctionException {
 209 
 210             return "Hello World";
 211         }
 212     }
 213 
 214     public class MyNamespaceContext implements NamespaceContext {
 215 
 216         public String getNamespaceURI(String prefix) {
 217             if (prefix == null) {
 218                 throw new IllegalArgumentException("The prefix cannot be null.");
 219             }
 220 
 221             if (prefix.equals("ext")) {
 222                 return "http://ext.com";
 223             } else {
 224                 return null;
 225             }
 226         }
 227 
 228         public String getPrefix(String namespace) {
 229 
 230             if (namespace == null) {
 231                 throw new IllegalArgumentException("The namespace uri cannot be null.");
 232             }
 233 
 234             if (namespace.equals("http://ext.com")) {
 235                 return "ext";
 236             } else {
 237                 return null;
 238             }
 239         }
 240 
 241         public Iterator getPrefixes(String namespace) {
 242             return null;
 243         }
 244     }
 245 
 246     boolean enableExtensionFunction(XPathFactory factory) {
 247         boolean isSupported = true;
 248         try {
 249             factory.setFeature(ENABLE_EXTENSION_FUNCTIONS, true);
 250         } catch (XPathFactoryConfigurationException ex) {
 251             isSupported = false;
 252         }
 253         return isSupported;
 254     }
 255 
 256     class SimplePolicy extends Policy {
 257 
 258         private final Permissions perms;
 259 
 260         public SimplePolicy(Permission... permissions) {
 261             perms = new Permissions();
 262             for (Permission permission : permissions) {
 263                 perms.add(permission);
 264             }
 265         }
 266 
 267         @Override
 268         public PermissionCollection getPermissions(CodeSource cs) {
 269             return perms;
 270         }
 271 
 272         @Override
 273         public PermissionCollection getPermissions(ProtectionDomain pd) {
 274             return perms;
 275         }
 276 
 277         @Override
 278         public boolean implies(ProtectionDomain pd, Permission p) {
 279             return perms.implies(p);
 280         }
 281 
 282         //for older jdk
 283         @Override
 284         public void refresh() {
 285         }
 286     }
 287 }