View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.xml.secure;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertInstanceOf;
23  import static org.junit.jupiter.api.Assertions.assertSame;
24  import static org.junit.jupiter.api.Assertions.assertThrows;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  
27  import java.lang.reflect.InvocationTargetException;
28  import java.lang.reflect.Method;
29  
30  import javax.xml.transform.TransformerFactory;
31  import javax.xml.transform.TransformerFactoryConfigurationError;
32  import javax.xml.xpath.XPathFactory;
33  
34  import org.junit.jupiter.api.Tag;
35  import org.junit.jupiter.api.Test;
36  import org.xml.sax.SAXNotSupportedException;
37  import org.xml.sax.helpers.XMLFilterImpl;
38  
39  class SaxonProviderTest {
40  
41      /**
42       * Reader used to force SecureConfiguration.makeParser through its SecureException translation path.
43       */
44      public static final class FailingXMLReader extends XMLFilterImpl {
45  
46          /**
47           * Always throws {@link SAXNotSupportedException}.
48           *
49           * @throws SAXNotSupportedException Thrown on every invocation.
50           */
51          @Override
52          public void setFeature(final String name, final boolean value) throws SAXNotSupportedException {
53              throw new SAXNotSupportedException(name);
54          }
55      }
56  
57      private static Class<?> loadSaxon(final String className) {
58          try {
59              return Class.forName(className);
60          } catch (final ClassNotFoundException e) {
61              throw new AssertionError(e);
62          }
63      }
64  
65      private static Object newSaxon(final String className) throws ReflectiveOperationException {
66          return loadSaxon(className).getConstructor().newInstance();
67      }
68  
69      @Test
70      @Tag("xpath3")
71      void configuresSaxonFactoriesAndSuppliesAnEmptySource() throws ReflectiveOperationException {
72          final TransformerFactory transformerFactory = TransformerFactory.class.cast(newSaxon("net.sf.saxon.TransformerFactoryImpl"));
73          final XPathFactory xpathFactory = XPathFactory.class.cast(newSaxon("net.sf.saxon.xpath.XPathFactoryImpl"));
74          assertSame(transformerFactory, SaxonProvider.configure(transformerFactory));
75          assertSame(xpathFactory, SaxonProvider.configure(xpathFactory));
76          assertEquals("net.sf.saxon.lib.EmptySource", SaxonProvider.emptySourceSupplier().get().getClass().getName());
77      }
78  
79      @Test
80      void recognizesNonSaxonClass() {
81          assertFalse(SaxonProvider.isSaxon(getClass()));
82      }
83  
84      @Test
85      @Tag("xpath3")
86      void recognizesOpenSourceAndCommercialSaxonClasses() {
87          assertTrue(SaxonProvider.isSaxon(loadSaxon("net.sf.saxon.TransformerFactoryImpl")));
88          assertTrue(SaxonProvider.isSaxon(com.saxonica.ProviderMarker.class));
89      }
90  
91      @Test
92      @Tag("xpath3")
93      void rejectsFactoriesThatDoNotImplementSaxonApis() {
94          assertThrows(SecureException.class,
95                  () -> SaxonProvider.configure(TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null)));
96          assertThrows(SecureException.class, () -> SaxonProvider
97                  .configure(XPathFactory.newInstance(XPathFactory.DEFAULT_OBJECT_MODEL_URI, "com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", null)));
98      }
99  
100     @Test
101     @Tag("xpath3")
102     void rejectsSaxonCollectionResolutionWhenConfiguredToThrow() throws Exception {
103         final XPathFactory factory = XPathFactory.class.cast(newSaxon("net.sf.saxon.xpath.XPathFactoryImpl"));
104         SaxonProvider.configure(factory);
105         final Object configuration = factory.getClass().getMethod("getConfiguration").invoke(factory);
106         final Object finder = configuration.getClass().getMethod("getCollectionFinder").invoke(configuration);
107         final Method findCollection = finder.getClass().getMethod("findCollection", loadSaxon("net.sf.saxon.expr.XPathContext"),
108                 String.class);
109         final String previous = System.getProperty(SecureException.THROW_ON_UNRESOLVED);
110         try {
111             System.setProperty(SecureException.THROW_ON_UNRESOLVED, "true");
112             final InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> findCollection.invoke(finder, null, "urn:collection"));
113             assertEquals("net.sf.saxon.trans.XPathException", exception.getCause().getClass().getName());
114         } finally {
115             if (previous == null) {
116                 System.clearProperty(SecureException.THROW_ON_UNRESOLVED);
117             } else {
118                 System.setProperty(SecureException.THROW_ON_UNRESOLVED, previous);
119             }
120         }
121     }
122 
123     @Test
124     @Tag("xpath3")
125     void translatesSecureParserFailuresToSaxonConfigurationErrors() throws Exception {
126         final TransformerFactory factory = TransformerFactory.class.cast(newSaxon("net.sf.saxon.TransformerFactoryImpl"));
127         SaxonProvider.configure(factory);
128         final Object configuration = factory.getClass().getMethod("getConfiguration").invoke(factory);
129         final Method makeParser = configuration.getClass().getMethod("makeParser", String.class);
130         final InvocationTargetException exception = assertThrows(InvocationTargetException.class, () -> makeParser.invoke(configuration, FailingXMLReader.class.getName()));
131         final TransformerFactoryConfigurationError error = assertInstanceOf(TransformerFactoryConfigurationError.class, exception.getCause());
132         assertInstanceOf(SecureException.class, error.getException());
133     }
134 }