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.assertInstanceOf;
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertNull;
23  import static org.junit.jupiter.api.Assertions.assertSame;
24  
25  import java.util.Locale;
26  
27  import javax.xml.parsers.SAXParser;
28  import javax.xml.parsers.SAXParserFactory;
29  import javax.xml.validation.Schema;
30  
31  import org.junit.jupiter.api.Tag;
32  import org.junit.jupiter.api.Test;
33  import org.xml.sax.DocumentHandler;
34  import org.xml.sax.Parser;
35  import org.xml.sax.SAXNotRecognizedException;
36  import org.xml.sax.SAXNotSupportedException;
37  import org.xml.sax.XMLReader;
38  
39  @Tag("sax")
40  class SecureSAXParserTest {
41  
42      private static final class ParserSecureReader extends SecureXMLReader implements Parser {
43  
44          ParserSecureReader(final XMLReader reader) {
45              super(reader);
46          }
47  
48          @Override
49          public void setDocumentHandler(final DocumentHandler handler) {
50          }
51  
52          @Override
53          public void setLocale(final Locale locale) {
54          }
55      }
56  
57      private static final class ReaderSAXParser extends SAXParser {
58  
59          private final XMLReader reader;
60  
61          ReaderSAXParser(final XMLReader reader) {
62              this.reader = reader;
63          }
64  
65          @Override
66          public Parser getParser() {
67              return (Parser) reader;
68          }
69  
70          @Override
71          public Object getProperty(final String name) throws SAXNotRecognizedException, SAXNotSupportedException {
72              return reader.getProperty(name);
73          }
74  
75          @Override
76          public Schema getSchema() {
77              return null;
78          }
79  
80          @Override
81          public XMLReader getXMLReader() {
82              return reader;
83          }
84  
85          @Override
86          public boolean isNamespaceAware() {
87              return false;
88          }
89  
90          @Override
91          public boolean isValidating() {
92              return false;
93          }
94  
95          @Override
96          public boolean isXIncludeAware() {
97              return false;
98          }
99  
100         @Override
101         public void reset() {
102         }
103 
104         @Override
105         public void setProperty(final String name, final Object value) throws SAXNotRecognizedException, SAXNotSupportedException {
106             reader.setProperty(name, value);
107         }
108     }
109 
110     @Test
111     void cachesSecureViewsAndKeepsThemSecuredAfterReset() throws Exception {
112         final SecureSAXParser parser = new SecureSAXParser(SAXParserFactory.newInstance().newSAXParser());
113         final XMLReader firstReader = parser.getXMLReader();
114         final Parser firstParser = parser.getParser();
115         assertSame(firstReader, parser.getXMLReader());
116         assertSame(firstParser, parser.getParser());
117         parser.setProperty("http://xml.org/sax/properties/lexical-handler", null);
118         assertNull(parser.getProperty("http://xml.org/sax/properties/lexical-handler"));
119         parser.reset();
120         // The views survive the reset rather than being recreated: a caller holding one from before keeps parsing on the floor the reset stripped.
121         assertSame(firstReader, parser.getXMLReader());
122         assertSame(firstParser, parser.getParser());
123         assertInstanceOf(FallbackIgnoreEntityResolver2.class, ((SecureXMLReader) firstReader).getDelegate().getEntityResolver(),
124                 "the reset must put the floor back on the underlying reader");
125     }
126 
127     @Test
128     void exposesSecureParserViewsAndState() throws Exception {
129         final SecureSAXParser parser = new SecureSAXParser(SAXParserFactory.newInstance().newSAXParser());
130         assertNotNull(parser.getXMLReader());
131         assertNotNull(parser.getParser());
132         parser.isNamespaceAware();
133         parser.isValidating();
134         if (AttackTestSupport.SAX_SUPPORTS_SCHEMA) {
135             parser.getSchema();
136         }
137         if (AttackTestSupport.SAX_SUPPORTS_XINCLUDE) {
138             parser.isXIncludeAware();
139         }
140         if (AttackTestSupport.SAX_SUPPORTS_RESET) {
141             parser.reset();
142         }
143     }
144 
145     @Test
146     void reusesAReaderThatAlreadyImplementsSax1Parser() throws Exception {
147         final ParserSecureReader reader = new ParserSecureReader(SAXParserFactory.newInstance().newSAXParser().getXMLReader());
148         final SecureSAXParser parser = new SecureSAXParser(new ReaderSAXParser(reader));
149         assertSame(reader, parser.getParser());
150     }
151 }