TestDisableExternalEntities.java
package com.ctc.wstx.msv;
import java.io.StringReader;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLStreamException;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.xml.sax.SAXNotRecognizedException;
import com.ctc.wstx.api.WstxInputProperties;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
/**
* Unit tests for {@link BaseSchemaFactory#disableExternalEntities}: failure to
* disable external entities must not be silently ignored.
*/
class TestDisableExternalEntities extends wstxtest.BaseJUnit4Test
{
private final static String FEATURE_GENERAL = "http://xml.org/sax/features/external-general-entities";
private final static String FEATURE_PARAM = "http://xml.org/sax/features/external-parameter-entities";
private final static String FEATURE_LOAD_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
@Test
void testFailsIfGeneralEntitiesNotSupported() throws Exception
{
_verifyFailsFor(FEATURE_GENERAL);
}
@Test
void testFailsIfParameterEntitiesNotSupported() throws Exception
{
_verifyFailsFor(FEATURE_PARAM);
}
// Xerces-specific feature, so lack of support is fine
@Test
void testLoadExternalDtdOptional() throws Exception
{
SAXParserFactory f = Mockito.mock(SAXParserFactory.class);
Mockito.doThrow(new SAXNotRecognizedException(FEATURE_LOAD_DTD))
.when(f).setFeature(eq(FEATURE_LOAD_DTD), anyBoolean());
BaseSchemaFactory.disableExternalEntities(f);
Mockito.verify(f).setFeature(FEATURE_GENERAL, false);
Mockito.verify(f).setFeature(FEATURE_PARAM, false);
}
// Legacy no-arg accessor must return the secure factory
@SuppressWarnings("deprecation")
@Test
void testLegacyGetSaxFactory()
{
assertSame(BaseSchemaFactory.getSaxFactory(false), BaseSchemaFactory.getSaxFactory());
}
// Schema loading must report the failure as declared XMLStreamException,
// not as unchecked exception
@Test
void testSchemaLoadingReportsStreamException() throws Exception
{
final String PROP = "javax.xml.parsers.SAXParserFactory";
final String oldProp = System.getProperty(PROP);
final SAXParserFactory oldFactory;
synchronized (BaseSchemaFactory.class) {
oldFactory = BaseSchemaFactory.sSaxFactory;
BaseSchemaFactory.sSaxFactory = null;
}
System.setProperty(PROP, RejectingSAXParserFactory.class.getName());
try {
final String SCHEMA = "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'/>";
try {
new W3CSchemaFactory().createSchema(new StringReader(SCHEMA));
fail("Should have failed for W3CSchemaFactory");
} catch (XMLStreamException e) {
assertTrue(e.getMessage(), e.getMessage().contains(FEATURE_GENERAL));
}
try {
new W3CMultiSchemaFactory().createSchema(null, java.util.Collections.emptyMap());
fail("Should have failed for W3CMultiSchemaFactory");
} catch (XMLStreamException e) {
assertTrue(e.getMessage(), e.getMessage().contains(FEATURE_GENERAL));
}
} finally {
if (oldProp == null) {
System.clearProperty(PROP);
} else {
System.setProperty(PROP, oldProp);
}
synchronized (BaseSchemaFactory.class) {
BaseSchemaFactory.sSaxFactory = oldFactory;
}
}
}
/**
* SAX parser factory that recognizes no features; must be public for
* {@link SAXParserFactory#newInstance()} to instantiate it.
*/
public static class RejectingSAXParserFactory extends SAXParserFactory
{
@Override
public SAXParser newSAXParser() {
throw new UnsupportedOperationException();
}
@Override
public void setFeature(String name, boolean value) throws SAXNotRecognizedException {
throw new SAXNotRecognizedException(name);
}
@Override
public boolean getFeature(String name) throws SAXNotRecognizedException {
throw new SAXNotRecognizedException(name);
}
}
private void _verifyFailsFor(String feature) throws Exception
{
SAXParserFactory f = Mockito.mock(SAXParserFactory.class);
Mockito.doNothing().when(f).setFeature(anyString(), anyBoolean());
Mockito.doThrow(new SAXNotRecognizedException(feature))
.when(f).setFeature(eq(feature), anyBoolean());
try {
BaseSchemaFactory.disableExternalEntities(f);
fail("Should have failed when '"+feature+"' not supported");
} catch (IllegalStateException e) {
String msg = e.getMessage();
assertTrue("Unexpected message: "+msg, msg.contains(feature));
assertTrue("Unexpected message: "+msg,
msg.contains(WstxInputProperties.P_MSV_SCHEMA_EXTERNAL_ACCESS));
}
}
}