mirror of https://github.com/apache/ant-ivy
CVE-2022-46751 don't parse doctypes and access external entities by default
This commit is contained in:
parent
6ac4f36c9e
commit
2be17bc18b
|
|
@ -23,6 +23,8 @@ In order to work as you want, Ivy sometimes needs some settings. Actually, Ivy c
|
|||
|
||||
Settings are specified through an XML file, usually called `ivysettings.xml`. To configure Ivy from Ant, you just have to use the link:use/settings{outfilesuffix}[settings] datatype with the path of your settings file.
|
||||
|
||||
In addition certain link:systemproperties{outfilesuffix}[Java system properties] affect the XML parsing behavior of Ivy.
|
||||
|
||||
Here is an example of the settings file:
|
||||
|
||||
[source, xml]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
////
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
////
|
||||
|
||||
= Java System Properties Affecting Ivy
|
||||
|
||||
== XML Parser Settings
|
||||
|
||||
Starting with Ivy 2.5.2 Ivy's XML parser can be controlled via the use
|
||||
of two newly introduced system properties.
|
||||
|
||||
If you want to restore the default behavior of Ivy 2.5.1 and earlier
|
||||
you need to set `ivy.xml.allow-doctype-processing` to `true` and
|
||||
`ivy.xml.external-resources` to `ALL`.
|
||||
|
||||
=== `ivy.xml.allow-doctype-processing`
|
||||
|
||||
This system property accepts `true` or `false` as values. When set to
|
||||
`false` Ivy will not allow any processing of doctype declarations at
|
||||
all, while setting it to `true` enables it.
|
||||
|
||||
The default is to allow doctype processing if and only if Ivy is
|
||||
parsing a Maven POM file.
|
||||
|
||||
=== `ivy.xml.external-resources`
|
||||
|
||||
This system property controls if external resources are read during
|
||||
doctype processing - and if so, where they can be loadad from. The
|
||||
value of this system property is only ever used if
|
||||
`ivy.xml.allow-doctype-processing` is not `false`.
|
||||
|
||||
The accepted values are
|
||||
|
||||
* `PROHIBIT` makes Ivy fail if any doctype tries to load an external
|
||||
resource.
|
||||
* `IGNORE` makes Ivy ignore any external resource that the doctype
|
||||
declaration wants to load.
|
||||
* `LOCAL_ONLY` allows external resources to be loaded via `file:` or
|
||||
`jar:file` URIs only.
|
||||
* `ALL` allows external resources to be loaded from any URI.
|
||||
|
||||
The default behavior is to not allow doctype processing at all, but if
|
||||
it is enabled the value `PROHIBIT` is assumed unless the property has
|
||||
been set explicitly.
|
||||
|
||||
When reading Maven POMs a specific internal system id is recognized as
|
||||
resource and will be loaded from a resource shipping with the Ivy
|
||||
distribution in order to deal with invalid POM files accepted by
|
||||
Apache Maven - and the default value for this property is
|
||||
`IGNORE`in that case. See
|
||||
link:https://issues.apache.org/jira/browse/IVY-921[IVY-921] for
|
||||
details.
|
||||
|
|
@ -150,6 +150,11 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "systemproperties",
|
||||
"title": "System Properties",
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id":"settings",
|
||||
"title":"Settings Files",
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ import java.util.Set;
|
|||
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerFactoryConfigurationError;
|
||||
import javax.xml.transform.sax.SAXTransformerFactory;
|
||||
import javax.xml.transform.sax.TransformerHandler;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
|
|
@ -43,6 +41,7 @@ import org.apache.ivy.core.resolve.IvyNode;
|
|||
import org.apache.ivy.core.resolve.ResolveOptions;
|
||||
import org.apache.ivy.core.resolve.ResolvedModuleRevision;
|
||||
import org.apache.ivy.core.retrieve.RetrieveOptions;
|
||||
import org.apache.ivy.util.XMLHelper;
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.Project;
|
||||
import org.xml.sax.SAXException;
|
||||
|
|
@ -170,10 +169,8 @@ public class IvyArtifactReport extends IvyPostResolveTask {
|
|||
}
|
||||
|
||||
private TransformerHandler createTransformerHandler(FileOutputStream fileOutputStream)
|
||||
throws TransformerFactoryConfigurationError, TransformerConfigurationException {
|
||||
SAXTransformerFactory transformerFact = (SAXTransformerFactory) SAXTransformerFactory
|
||||
.newInstance();
|
||||
TransformerHandler saxHandler = transformerFact.newTransformerHandler();
|
||||
throws TransformerConfigurationException {
|
||||
TransformerHandler saxHandler = XMLHelper.getTransformerHandler();
|
||||
saxHandler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8");
|
||||
saxHandler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
saxHandler.setResult(new StreamResult(fileOutputStream));
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import javax.xml.transform.Source;
|
|||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
|
|
@ -48,6 +47,7 @@ import org.apache.ivy.plugins.report.XmlReportOutputter;
|
|||
import org.apache.ivy.plugins.report.XmlReportParser;
|
||||
import org.apache.ivy.util.FileUtil;
|
||||
import org.apache.ivy.util.Message;
|
||||
import org.apache.ivy.util.XMLHelper;
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.taskdefs.XSLTProcess;
|
||||
import org.apache.tools.ant.util.JAXPUtils;
|
||||
|
|
@ -313,8 +313,7 @@ public class IvyReport extends IvyTask {
|
|||
Source xsltSource = new StreamSource(xsltStream, JAXPUtils.getSystemId(style));
|
||||
|
||||
// create transformer
|
||||
TransformerFactory tFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = tFactory.newTransformer(xsltSource);
|
||||
Transformer transformer = XMLHelper.getTransformer(xsltSource);
|
||||
|
||||
// add standard parameters
|
||||
transformer.setParameter("confs", conf);
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.apache.ivy.core.IvyPatternHelper;
|
||||
import org.apache.ivy.core.cache.RepositoryCacheManager;
|
||||
import org.apache.ivy.core.module.status.StatusManager;
|
||||
|
|
@ -46,6 +44,7 @@ import org.apache.ivy.util.Checks;
|
|||
import org.apache.ivy.util.Configurator;
|
||||
import org.apache.ivy.util.FileResolver;
|
||||
import org.apache.ivy.util.Message;
|
||||
import org.apache.ivy.util.XMLHelper;
|
||||
import org.apache.ivy.util.url.CredentialsStore;
|
||||
import org.apache.ivy.util.url.TimeoutConstrainedURLHandler;
|
||||
import org.apache.ivy.util.url.URLHandlerRegistry;
|
||||
|
|
@ -151,10 +150,8 @@ public class XmlSettingsParser extends DefaultHandler {
|
|||
@SuppressWarnings("deprecation")
|
||||
private void doParse(URL settingsUrl) throws IOException, ParseException {
|
||||
this.settings = settingsUrl;
|
||||
try (InputStream stream = URLHandlerRegistry.getDefault().openStream(settingsUrl)) {
|
||||
InputSource inSrc = new InputSource(stream);
|
||||
inSrc.setSystemId(settingsUrl.toExternalForm());
|
||||
SAXParserFactory.newInstance().newSAXParser().parse(settingsUrl.toExternalForm(), this);
|
||||
try {
|
||||
XMLHelper.parse(settingsUrl, null, this);
|
||||
ivy.validate();
|
||||
} catch (IOException e) {
|
||||
throw e;
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@ import java.text.ParseException;
|
|||
import java.util.Set;
|
||||
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.sax.SAXTransformerFactory;
|
||||
import javax.xml.transform.sax.TransformerHandler;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
|
|
@ -45,6 +43,7 @@ import org.apache.ivy.osgi.repo.ManifestAndLocation;
|
|||
import org.apache.ivy.osgi.util.Version;
|
||||
import org.apache.ivy.osgi.util.VersionRange;
|
||||
import org.apache.ivy.util.Message;
|
||||
import org.apache.ivy.util.XMLHelper;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
|
@ -53,12 +52,10 @@ public class OBRXMLWriter {
|
|||
|
||||
public static ContentHandler newHandler(OutputStream out, String encoding, boolean indent)
|
||||
throws TransformerConfigurationException {
|
||||
SAXTransformerFactory tf = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
|
||||
TransformerHandler hd = tf.newTransformerHandler();
|
||||
Transformer serializer = tf.newTransformer();
|
||||
TransformerHandler hd = XMLHelper.getTransformerHandler();
|
||||
hd.getTransformer().setOutputProperty(OutputKeys.ENCODING, encoding);
|
||||
hd.getTransformer().setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no");
|
||||
StreamResult stream = new StreamResult(out);
|
||||
serializer.setOutputProperty(OutputKeys.ENCODING, encoding);
|
||||
serializer.setOutputProperty(OutputKeys.INDENT, indent ? "yes" : "no");
|
||||
hd.setResult(stream);
|
||||
return hd;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,12 +130,13 @@ public class PomReader {
|
|||
public InputSource resolveEntity(String publicId, String systemId)
|
||||
throws SAXException, IOException {
|
||||
if (systemId != null && systemId.endsWith("m2-entities.ent")) {
|
||||
// IVY-921: return an InputSource for our local packaged m2-entities.ent file
|
||||
return new InputSource(
|
||||
PomReader.class.getResourceAsStream("m2-entities.ent"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, true, XMLHelper.ExternalResources.IGNORE);
|
||||
projectElement = pomDomDoc.getDocumentElement();
|
||||
if (!PROJECT.equals(projectElement.getNodeName())
|
||||
&& !MODEL.equals(projectElement.getNodeName())) {
|
||||
|
|
|
|||
|
|
@ -17,9 +17,13 @@
|
|||
*/
|
||||
package org.apache.ivy.plugins.parser.xml;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.StringReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
|
@ -80,6 +84,7 @@ import org.apache.ivy.util.Message;
|
|||
import org.apache.ivy.util.XMLHelper;
|
||||
import org.apache.ivy.util.extendable.ExtendableItemHelper;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import static org.apache.ivy.core.module.descriptor.Configuration.Visibility.getVisibility;
|
||||
|
|
@ -216,6 +221,8 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser {
|
|||
protected static final List<String> ALLOWED_VERSIONS = Arrays.asList("1.0",
|
||||
"1.1", "1.2", "1.3", "1.4", "2.0", "2.1", "2.2", "2.3", "2.4");
|
||||
|
||||
private static final String IVY_XSD_CONTENT;
|
||||
|
||||
/* how and what do we have to parse */
|
||||
private ParserSettings settings;
|
||||
|
||||
|
|
@ -248,6 +255,40 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser {
|
|||
|
||||
private Stack<ExtraInfoHolder> extraInfoStack = new Stack<>();
|
||||
|
||||
static {
|
||||
String ivyXSDContent = null;
|
||||
final InputStream is = Parser.class.getResourceAsStream("ivy.xsd");
|
||||
if (is != null) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
try {
|
||||
try {
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (sb.length() != 0) {
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(line);
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// ignore
|
||||
ivyXSDContent = null;
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
ivyXSDContent = null;
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
ivyXSDContent = sb.length() == 0 ? null : sb.toString();
|
||||
}
|
||||
IVY_XSD_CONTENT = ivyXSDContent;
|
||||
}
|
||||
|
||||
public Parser(ModuleDescriptorParser parser, ParserSettings ivySettings) {
|
||||
super(parser);
|
||||
settings = ivySettings;
|
||||
|
|
@ -268,10 +309,14 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser {
|
|||
public void parse() throws ParseException {
|
||||
try {
|
||||
URL schemaURL = validate ? getSchemaURL() : null;
|
||||
XMLHelper.ExternalResources e =
|
||||
validate && System.getProperty(XMLHelper.EXTERNAL_RESOURCES) == null
|
||||
? XMLHelper.ExternalResources.IGNORE
|
||||
: XMLHelper.ExternalResources.fromSystemProperty();
|
||||
if (descriptorURL != null) {
|
||||
XMLHelper.parse(descriptorURL, schemaURL, this);
|
||||
XMLHelper.parse(descriptorURL, schemaURL, this, null, e);
|
||||
} else {
|
||||
XMLHelper.parse(descriptorInput, schemaURL, this, null);
|
||||
XMLHelper.parse(descriptorInput, schemaURL, this, null, e);
|
||||
}
|
||||
checkConfigurations();
|
||||
replaceConfigurationWildcards();
|
||||
|
|
@ -296,6 +341,26 @@ public class XmlModuleDescriptorParser extends AbstractModuleDescriptorParser {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputSource resolveEntity(final String publicId, final String systemId)
|
||||
throws IOException, SAXException {
|
||||
if (isApacheOrgIvyXSDSystemId(systemId) && IVY_XSD_CONTENT != null) {
|
||||
// redirect the schema location to local file based ivy.xsd whose content
|
||||
// we have already read and is available in-memory.
|
||||
final InputSource source = new InputSource(new StringReader(IVY_XSD_CONTENT));
|
||||
return source;
|
||||
}
|
||||
return super.resolveEntity(publicId, systemId);
|
||||
}
|
||||
|
||||
private static boolean isApacheOrgIvyXSDSystemId(final String systemId) {
|
||||
if (systemId == null) {
|
||||
return false;
|
||||
}
|
||||
return systemId.equals("http://ant.apache.org/ivy/schemas/ivy.xsd")
|
||||
|| systemId.equals("https://ant.apache.org/ivy/schemas/ivy.xsd");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes)
|
||||
throws SAXException {
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@ import java.util.Map;
|
|||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
import org.apache.ivy.core.cache.ArtifactOrigin;
|
||||
import org.apache.ivy.core.module.descriptor.Artifact;
|
||||
import org.apache.ivy.core.module.descriptor.DefaultArtifact;
|
||||
|
|
@ -38,6 +35,7 @@ import org.apache.ivy.core.report.ArtifactDownloadReport;
|
|||
import org.apache.ivy.core.report.DownloadStatus;
|
||||
import org.apache.ivy.core.report.MetadataArtifactDownloadReport;
|
||||
import org.apache.ivy.util.DateUtil;
|
||||
import org.apache.ivy.util.XMLHelper;
|
||||
import org.apache.ivy.util.extendable.ExtendableItemHelper;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
|
|
@ -242,8 +240,7 @@ public class XmlReportParser {
|
|||
}
|
||||
|
||||
public void parse() throws Exception {
|
||||
SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
|
||||
saxParser.parse(report, new XmlReportParserHandler());
|
||||
XMLHelper.parse(report.toURI().toURL(), null, new XmlReportParserHandler());
|
||||
}
|
||||
|
||||
private static boolean parseBoolean(String str) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.ivy.util;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
|
|
@ -28,13 +29,24 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
|||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.sax.SAXTransformerFactory;
|
||||
import javax.xml.transform.sax.TransformerHandler;
|
||||
|
||||
import org.apache.ivy.util.url.URLHandlerRegistry;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.Locator;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXNotRecognizedException;
|
||||
import org.xml.sax.SAXNotSupportedException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.xml.sax.XMLReader;
|
||||
import org.xml.sax.ext.LexicalHandler;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
|
|
@ -50,49 +62,38 @@ public abstract class XMLHelper {
|
|||
|
||||
static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
|
||||
|
||||
private static boolean canUseSchemaValidation = true;
|
||||
private static final String XML_ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema";
|
||||
private static final String XML_ACCESS_EXTERNAL_DTD = "http://javax.xml.XMLConstants/property/accessExternalDTD";
|
||||
public static final String ALLOW_DOCTYPE_PROCESSING = "ivy.xml.allow-doctype-processing";
|
||||
public static final String EXTERNAL_RESOURCES = "ivy.xml.external-resources";
|
||||
|
||||
private static Boolean canDisableExternalDtds = null;
|
||||
|
||||
private static SAXParser newSAXParser(URL schema, InputStream schemaStream,
|
||||
boolean loadExternalDtds) throws ParserConfigurationException, SAXException {
|
||||
SAXParserFactory parserFactory = SAXParserFactory.newInstance();
|
||||
private static SAXParser newSAXParser(final URL schema, final InputStream schemaStream,
|
||||
final boolean allowXmlDoctypeProcessing, final ExternalResources externalResources)
|
||||
throws ParserConfigurationException, SAXException {
|
||||
final SAXParserFactory parserFactory = SAXParserFactory.newInstance();
|
||||
parserFactory.setNamespaceAware(true);
|
||||
parserFactory.setValidating(canUseSchemaValidation && (schema != null));
|
||||
if (!loadExternalDtds && canDisableExternalDtds(parserFactory)) {
|
||||
parserFactory.setFeature(XERCES_LOAD_EXTERNAL_DTD, false);
|
||||
}
|
||||
SAXParser parser = parserFactory.newSAXParser();
|
||||
parserFactory.setValidating(schema != null);
|
||||
configureSafeFeatures(parserFactory, allowXmlDoctypeProcessing, externalResources);
|
||||
|
||||
if (canUseSchemaValidation && schema != null) {
|
||||
SAXParser parser = parserFactory.newSAXParser();
|
||||
if (schema != null) {
|
||||
try {
|
||||
parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
|
||||
parser.setProperty(JAXP_SCHEMA_SOURCE, schemaStream);
|
||||
} catch (SAXNotRecognizedException ex) {
|
||||
Message.warn("problem while setting JAXP validating property on SAXParser... "
|
||||
+ "XML validation will not be done", ex);
|
||||
canUseSchemaValidation = false;
|
||||
parserFactory.setValidating(false);
|
||||
parser = parserFactory.newSAXParser();
|
||||
}
|
||||
}
|
||||
|
||||
parser.getXMLReader().setFeature(XML_NAMESPACE_PREFIXES, true);
|
||||
final XMLReader reader = parser.getXMLReader();
|
||||
reader.setFeature(XML_NAMESPACE_PREFIXES, true);
|
||||
reader.setProperty(XML_ACCESS_EXTERNAL_SCHEMA, externalResources.getAllowedProtocols());
|
||||
reader.setProperty(XML_ACCESS_EXTERNAL_DTD, externalResources.getAllowedProtocols());
|
||||
return parser;
|
||||
}
|
||||
|
||||
private static boolean canDisableExternalDtds(SAXParserFactory parserFactory) {
|
||||
if (canDisableExternalDtds == null) {
|
||||
try {
|
||||
parserFactory.getFeature(XERCES_LOAD_EXTERNAL_DTD);
|
||||
canDisableExternalDtds = Boolean.TRUE;
|
||||
} catch (Exception ex) {
|
||||
canDisableExternalDtds = Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
return canDisableExternalDtds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an URL to a valid systemId according to RFC 2396.
|
||||
*
|
||||
|
|
@ -116,36 +117,58 @@ public abstract class XMLHelper {
|
|||
parse(xmlURL, schema, handler, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void parse(URL xmlURL, URL schema, DefaultHandler handler, LexicalHandler lHandler)
|
||||
throws SAXException, IOException, ParserConfigurationException {
|
||||
parse(xmlURL, schema, handler, lHandler, ExternalResources.fromSystemProperty());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void parse(URL xmlURL, URL schema, DefaultHandler handler, LexicalHandler lHandler,
|
||||
final ExternalResources externalResources)
|
||||
throws SAXException, IOException, ParserConfigurationException {
|
||||
try (InputStream xmlStream = URLHandlerRegistry.getDefault().openStream(xmlURL)) {
|
||||
InputSource inSrc = new InputSource(xmlStream);
|
||||
inSrc.setSystemId(toSystemId(xmlURL));
|
||||
parse(inSrc, schema, handler, lHandler);
|
||||
parse(inSrc, schema, handler, lHandler, externalResources);
|
||||
}
|
||||
}
|
||||
|
||||
public static void parse(InputStream xmlStream, URL schema, DefaultHandler handler,
|
||||
LexicalHandler lHandler) throws SAXException, IOException, ParserConfigurationException {
|
||||
parse(xmlStream, schema, handler, lHandler, ExternalResources.fromSystemProperty());
|
||||
}
|
||||
|
||||
public static void parse(InputStream xmlStream, URL schema, DefaultHandler handler,
|
||||
LexicalHandler lHandler, final ExternalResources externalResources)
|
||||
throws SAXException, IOException, ParserConfigurationException {
|
||||
parse(new InputSource(xmlStream), schema, handler, lHandler);
|
||||
}
|
||||
|
||||
public static void parse(InputSource xmlStream, URL schema, DefaultHandler handler,
|
||||
LexicalHandler lHandler) throws SAXException, IOException, ParserConfigurationException {
|
||||
parse(xmlStream, schema, handler, lHandler, true);
|
||||
parse(xmlStream, schema, handler, lHandler, ExternalResources.fromSystemProperty());
|
||||
}
|
||||
|
||||
public static void parse(final InputSource xmlStream, final URL schema,
|
||||
final DefaultHandler handler, final LexicalHandler lHandler,
|
||||
final boolean loadExternalDtds) throws SAXException, IOException,
|
||||
ParserConfigurationException {
|
||||
parse(xmlStream, schema, handler, lHandler,
|
||||
loadExternalDtds ? ExternalResources.LOCAL_ONLY : ExternalResources.PROHIBIT);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void parse(InputSource xmlStream, URL schema, DefaultHandler handler,
|
||||
LexicalHandler lHandler, boolean loadExternalDtds) throws SAXException, IOException,
|
||||
public static void parse(final InputSource xmlStream, final URL schema,
|
||||
final DefaultHandler handler, final LexicalHandler lHandler,
|
||||
final ExternalResources externalResources) throws SAXException, IOException,
|
||||
ParserConfigurationException {
|
||||
InputStream schemaStream = null;
|
||||
try {
|
||||
if (schema != null) {
|
||||
schemaStream = URLHandlerRegistry.getDefault().openStream(schema);
|
||||
}
|
||||
SAXParser parser = XMLHelper.newSAXParser(schema, schemaStream, loadExternalDtds);
|
||||
SAXParser parser = XMLHelper.newSAXParser(schema, schemaStream,
|
||||
isXmlDoctypeProcessingAllowed(), externalResources);
|
||||
|
||||
if (lHandler != null) {
|
||||
try {
|
||||
|
|
@ -157,7 +180,10 @@ public abstract class XMLHelper {
|
|||
}
|
||||
}
|
||||
|
||||
parser.parse(xmlStream, handler);
|
||||
DefaultHandler h = externalResources == ExternalResources.IGNORE
|
||||
? new NoopEntityResolverDefaultHandler(handler)
|
||||
: handler;
|
||||
parser.parse(xmlStream, h);
|
||||
} finally {
|
||||
if (schemaStream != null) {
|
||||
try {
|
||||
|
|
@ -170,7 +196,7 @@ public abstract class XMLHelper {
|
|||
}
|
||||
|
||||
public static boolean canUseSchemaValidation() {
|
||||
return canUseSchemaValidation;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -216,15 +242,33 @@ public abstract class XMLHelper {
|
|||
|
||||
public static Document parseToDom(InputSource source, EntityResolver entityResolver)
|
||||
throws IOException, SAXException {
|
||||
DocumentBuilder docBuilder = getDocBuilder(entityResolver);
|
||||
return parseToDom(source, entityResolver, isXmlDoctypeProcessingAllowed(),
|
||||
ExternalResources.fromSystemProperty());
|
||||
}
|
||||
|
||||
public static Document parseToDom(InputSource source, EntityResolver entityResolver,
|
||||
boolean allowXmlDoctypeProcessing, ExternalResources externalResources)
|
||||
throws IOException, SAXException {
|
||||
DocumentBuilder docBuilder = getDocBuilder(entityResolver, allowXmlDoctypeProcessing,
|
||||
externalResources);
|
||||
return docBuilder.parse(source);
|
||||
}
|
||||
|
||||
public static DocumentBuilder getDocBuilder(EntityResolver entityResolver) {
|
||||
return getDocBuilder(entityResolver, isXmlDoctypeProcessingAllowed(),
|
||||
ExternalResources.fromSystemProperty());
|
||||
}
|
||||
|
||||
public static DocumentBuilder getDocBuilder(EntityResolver entityResolver,
|
||||
boolean allowXmlDoctypeProcessing, ExternalResources externalResources) {
|
||||
try {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setValidating(false);
|
||||
configureSafeFeatures(factory, allowXmlDoctypeProcessing, externalResources);
|
||||
DocumentBuilder docBuilder = factory.newDocumentBuilder();
|
||||
if (externalResources == ExternalResources.IGNORE) {
|
||||
entityResolver = new NoopEntityResolver(entityResolver);
|
||||
}
|
||||
if (entityResolver != null) {
|
||||
docBuilder.setEntityResolver(entityResolver);
|
||||
}
|
||||
|
|
@ -234,7 +278,335 @@ public abstract class XMLHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static Transformer getTransformer(Source source) throws TransformerConfigurationException {
|
||||
TransformerFactory factory = getTransformerFactory();
|
||||
return factory.newTransformer(source);
|
||||
}
|
||||
|
||||
public static TransformerHandler getTransformerHandler() throws TransformerConfigurationException {
|
||||
SAXTransformerFactory factory = getTransformerFactory();
|
||||
return factory.newTransformerHandler();
|
||||
}
|
||||
|
||||
public enum ExternalResources {
|
||||
PROHIBIT(""),
|
||||
// technically the URIs for IGNORE will never get resolved at all.
|
||||
// "all" pacifies some version of Java that check the property before delegating to the EntityResolver (which is
|
||||
// going to return an empty content anyway)
|
||||
IGNORE("all"),
|
||||
LOCAL_ONLY("file, jar:file"),
|
||||
ALL("all");
|
||||
|
||||
private final String allowedProtocols;
|
||||
|
||||
private ExternalResources(String allowedProtocols) {
|
||||
this.allowedProtocols = allowedProtocols;
|
||||
}
|
||||
|
||||
private String getAllowedProtocols() {
|
||||
return allowedProtocols;
|
||||
}
|
||||
|
||||
public static ExternalResources fromSystemProperty() {
|
||||
final String val = System.getProperty(EXTERNAL_RESOURCES);
|
||||
if (val != null) {
|
||||
if (val.equalsIgnoreCase("ignore")) {
|
||||
return IGNORE;
|
||||
}
|
||||
if (val.equalsIgnoreCase("all")) {
|
||||
return ALL;
|
||||
}
|
||||
if (val.equalsIgnoreCase("local-only") || val.equalsIgnoreCase("local_only")) {
|
||||
return LOCAL_ONLY;
|
||||
}
|
||||
}
|
||||
return PROHIBIT;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isXmlDoctypeProcessingAllowed() {
|
||||
return "true".equals(System.getProperty(ALLOW_DOCTYPE_PROCESSING));
|
||||
}
|
||||
|
||||
private XMLHelper() {
|
||||
}
|
||||
|
||||
private static SAXTransformerFactory getTransformerFactory() {
|
||||
TransformerFactory factory = SAXTransformerFactory.newInstance();
|
||||
configureSafeFeatures(factory);
|
||||
return (SAXTransformerFactory) factory;
|
||||
}
|
||||
|
||||
private static void configureSafeFeatures(final DocumentBuilderFactory factory,
|
||||
final boolean allowXmlDoctypeProcessing, final ExternalResources externalResources) {
|
||||
final String DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
trySetFeature(factory, DISALLOW_DOCTYPE_DECL, !allowXmlDoctypeProcessing);
|
||||
|
||||
// available since Java 6, as XMLConstants.FEATURE_SECURE_PROCESSING. We can't use Java 6
|
||||
// at compile time, in current version, so inline the constant here
|
||||
final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||
trySetFeature(factory, FEATURE_SECURE_PROCESSING, true);
|
||||
|
||||
final String ALLOW_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
|
||||
trySetFeature(factory, ALLOW_EXTERNAL_GENERAL_ENTITIES, false);
|
||||
|
||||
final String ALLOW_EXTERNAL_PARAM_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
|
||||
trySetFeature(factory, ALLOW_EXTERNAL_PARAM_ENTITIES, false);
|
||||
|
||||
final String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
trySetFeature(factory, LOAD_EXTERNAL_DTD, externalResources != ExternalResources.PROHIBIT);
|
||||
|
||||
try {
|
||||
factory.setXIncludeAware(false);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
try {
|
||||
factory.setExpandEntityReferences(false);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static void configureSafeFeatures(final SAXParserFactory factory,
|
||||
final boolean allowXmlDoctypeProcessing, final ExternalResources externalResources) {
|
||||
final String DISALLOW_DOCTYPE_DECL = "http://apache.org/xml/features/disallow-doctype-decl";
|
||||
trySetFeature(factory, DISALLOW_DOCTYPE_DECL, !allowXmlDoctypeProcessing);
|
||||
|
||||
// available since Java 6, as XMLConstants.FEATURE_SECURE_PROCESSING. We can't use Java 6
|
||||
// at compile time, in current version, so inline the constant here
|
||||
final String FEATURE_SECURE_PROCESSING = "http://javax.xml.XMLConstants/feature/secure-processing";
|
||||
trySetFeature(factory, FEATURE_SECURE_PROCESSING, true);
|
||||
|
||||
final boolean allowEntities = externalResources == ExternalResources.LOCAL_ONLY
|
||||
|| externalResources == ExternalResources.ALL;
|
||||
final String ALLOW_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
|
||||
trySetFeature(factory, ALLOW_EXTERNAL_GENERAL_ENTITIES, allowEntities);
|
||||
|
||||
final String ALLOW_EXTERNAL_PARAM_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
|
||||
trySetFeature(factory, ALLOW_EXTERNAL_PARAM_ENTITIES, allowEntities);
|
||||
final String LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
|
||||
trySetFeature(factory, LOAD_EXTERNAL_DTD, externalResources != ExternalResources.PROHIBIT);
|
||||
try {
|
||||
factory.setXIncludeAware(false);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static void configureSafeFeatures(final TransformerFactory factory) {
|
||||
// available since Java 7, as XMLConstants.ACCESS_EXTERNAL_DTD, ACCESS_EXTERNAL_SCHEMA and
|
||||
// ACCESS_EXTERNAL_STYLESHEET respectively.
|
||||
// We can't use Java 7 at compile time, in current version, so inline the constants here
|
||||
trySetAttribute(factory, XML_ACCESS_EXTERNAL_DTD, "");
|
||||
trySetAttribute(factory, XML_ACCESS_EXTERNAL_SCHEMA, "");
|
||||
trySetAttribute(factory, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", "");
|
||||
}
|
||||
|
||||
private static boolean isFeatureSupported(final SAXParserFactory factory, final String feature) {
|
||||
try {
|
||||
factory.getFeature(feature);
|
||||
return true;
|
||||
} catch (ParserConfigurationException e) {
|
||||
return false;
|
||||
} catch (SAXNotRecognizedException e) {
|
||||
return false;
|
||||
} catch (SAXNotSupportedException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isFeatureSupported(final DocumentBuilderFactory factory, final String feature) {
|
||||
try {
|
||||
factory.getFeature(feature);
|
||||
return true;
|
||||
} catch (ParserConfigurationException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAttributeSupported(final TransformerFactory factory, final String attribute) {
|
||||
try {
|
||||
factory.getAttribute(attribute);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean trySetFeature(final DocumentBuilderFactory factory,
|
||||
final String feature, final boolean val) {
|
||||
if (!isFeatureSupported(factory, feature)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
factory.setFeature(feature, val);
|
||||
return true;
|
||||
} catch (ParserConfigurationException e) {
|
||||
// log and continue
|
||||
Message.warn("Failed to set feature " + feature + " on DocumentBuilderFactory", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean trySetFeature(final SAXParserFactory factory,
|
||||
final String feature, final boolean val) {
|
||||
if (!isFeatureSupported(factory, feature)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
factory.setFeature(feature, val);
|
||||
return true;
|
||||
} catch (ParserConfigurationException e) {
|
||||
// log and continue
|
||||
Message.warn("Failed to set feature " + feature + " on SAXParserFactory", e);
|
||||
return false;
|
||||
} catch (SAXNotRecognizedException e) {
|
||||
// log and continue
|
||||
Message.warn("Failed to set feature " + feature + " on SAXParserFactory", e);
|
||||
return false;
|
||||
} catch (SAXNotSupportedException e) {
|
||||
// log and continue
|
||||
Message.warn("Failed to set feature " + feature + " on SAXParserFactory", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean trySetAttribute(final TransformerFactory factory,
|
||||
final String attribute, final String val) {
|
||||
if (!isAttributeSupported(factory, attribute)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
factory.setAttribute(attribute, val);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
// log and continue
|
||||
Message.warn("Failed to set attribute " + attribute + " on TransformerFactory", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final InputSource EMPTY_INPUT_SOURCE = new InputSource(new StringReader(""));
|
||||
|
||||
private static class NoopEntityResolver implements EntityResolver {
|
||||
private EntityResolver wrapped;
|
||||
|
||||
private NoopEntityResolver(EntityResolver wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
|
||||
if (wrapped != null) {
|
||||
InputSource s = wrapped.resolveEntity(publicId, systemId);
|
||||
if (s != null) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return EMPTY_INPUT_SOURCE;
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoopEntityResolverDefaultHandler extends DefaultHandler {
|
||||
|
||||
private DefaultHandler wrapped;
|
||||
|
||||
private NoopEntityResolverDefaultHandler(DefaultHandler wrapped) {
|
||||
this.wrapped = wrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
|
||||
if (wrapped != null) {
|
||||
InputSource s = wrapped.resolveEntity(publicId, systemId);
|
||||
if (s != null) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return EMPTY_INPUT_SOURCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notationDecl(String name, String publicId, String systemId) throws SAXException {
|
||||
wrapped.notationDecl(name, publicId, systemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unparsedEntityDecl(String name, String publicId, String systemId, String notationName)
|
||||
throws SAXException {
|
||||
wrapped.unparsedEntityDecl(name, publicId, systemId, notationName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDocumentLocator(Locator locator) {
|
||||
wrapped.setDocumentLocator(locator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDocument() throws SAXException {
|
||||
wrapped.startDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDocument() throws SAXException {
|
||||
wrapped.endDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startPrefixMapping(String prefix, String uri) throws SAXException {
|
||||
wrapped.startPrefixMapping(prefix, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endPrefixMapping(String prefix) throws SAXException {
|
||||
wrapped.endPrefixMapping(prefix);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes)
|
||||
throws SAXException {
|
||||
wrapped.startElement(uri, localName, qName, attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endElement(String uri, String localName, String qName) throws SAXException {
|
||||
wrapped.endElement(uri, localName, qName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) throws SAXException {
|
||||
wrapped.characters(ch, start, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
|
||||
wrapped.ignorableWhitespace(ch, start, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processingInstruction(String target, String data) throws SAXException {
|
||||
wrapped.processingInstruction(target, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void skippedEntity(String name) throws SAXException {
|
||||
wrapped.skippedEntity(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warning(SAXParseException e) throws SAXException {
|
||||
wrapped.warning(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(SAXParseException e) throws SAXException {
|
||||
wrapped.error(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatalError(SAXParseException e) throws SAXException {
|
||||
wrapped.fatalError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import org.apache.ivy.plugins.resolver.FileSystemResolver;
|
|||
import org.apache.ivy.util.CacheCleaner;
|
||||
import org.apache.ivy.util.FileUtil;
|
||||
import org.apache.ivy.util.MockMessageLogger;
|
||||
import org.apache.ivy.util.XMLHelper;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
|
|
@ -74,6 +75,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
|
@ -309,6 +311,43 @@ public class ResolveTest {
|
|||
|
||||
@Test
|
||||
public void testResolveWithXmlEntities() {
|
||||
testResolveWithXmlEntities(null, 0);
|
||||
testResolveWithXmlEntities("prohibit", 0);
|
||||
testResolveWithXmlEntities("ignore", 0);
|
||||
testResolveWithXmlEntities("local-only", 2);
|
||||
testResolveWithXmlEntities("LOCAL_ONLY", 2);
|
||||
testResolveWithXmlEntities("all", 2);
|
||||
}
|
||||
|
||||
private void testResolveWithXmlEntities(String externalResourcesSystemProperty,
|
||||
int expectedNumberOfDependencies) {
|
||||
Ivy ivy = new Ivy();
|
||||
Throwable th = null;
|
||||
Properties p = System.getProperties();
|
||||
try {
|
||||
System.setProperties(new Properties());
|
||||
System.setProperty(XMLHelper.ALLOW_DOCTYPE_PROCESSING, "true");
|
||||
if (externalResourcesSystemProperty != null) {
|
||||
System.setProperty(XMLHelper.EXTERNAL_RESOURCES, externalResourcesSystemProperty);
|
||||
}
|
||||
ivy.configure(new File("test/repositories/xml-entities/ivysettings.xml"));
|
||||
ResolveReport report = ivy.resolve(new File("test/repositories/xml-entities/ivy.xml"),
|
||||
getResolveOptions(new String[] {"*"}));
|
||||
assertNotNull(report);
|
||||
assertFalse(report.hasError());
|
||||
assertNotNull(report.getDependencies());
|
||||
assertEquals("number of dependencies while setting " + externalResourcesSystemProperty,
|
||||
expectedNumberOfDependencies, report.getDependencies().size());
|
||||
} catch (Throwable e) {
|
||||
th = e;
|
||||
} finally {
|
||||
System.setProperties(p);
|
||||
}
|
||||
assertNull(th);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolveWithXmlEntitiesButNoSystemProperty() {
|
||||
Ivy ivy = new Ivy();
|
||||
Throwable th = null;
|
||||
try {
|
||||
|
|
@ -320,7 +359,7 @@ public class ResolveTest {
|
|||
} catch (Throwable e) {
|
||||
th = e;
|
||||
}
|
||||
assertNull(th);
|
||||
assertNotNull(th);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
Loading…
Reference in New Issue