diff --git a/bom/build.gradle.kts b/bom/build.gradle.kts index 5febf6f0b335..6d19bc352a1e 100644 --- a/bom/build.gradle.kts +++ b/bom/build.gradle.kts @@ -107,6 +107,7 @@ dependencies { apiv("org.apache.commons:commons-dbcp2") apiv("org.apache.commons:commons-math3") apiv("org.apache.commons:commons-pool2") + apiv("org.apache.commons:commons-secure-xml") apiv("org.apache.commons:commons-collections4") apiv("org.apache.commons:commons-text") apiv("org.apache.geode:geode-core") diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 086f114480e4..1a88bcd0df09 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -70,6 +70,7 @@ dependencies { implementation("net.hydromatic:aggdesigner-algorithm") implementation("org.apache.commons:commons-dbcp2") implementation("org.apache.commons:commons-math3") + implementation("org.apache.commons:commons-secure-xml") implementation("org.apache.commons:commons-text") implementation("org.jooq:joou-java-6") implementation("commons-io:commons-io") diff --git a/core/src/main/java/org/apache/calcite/runtime/SpatialTypeUtils.java b/core/src/main/java/org/apache/calcite/runtime/SpatialTypeUtils.java index f23514370e5a..ce3530106557 100644 --- a/core/src/main/java/org/apache/calcite/runtime/SpatialTypeUtils.java +++ b/core/src/main/java/org/apache/calcite/runtime/SpatialTypeUtils.java @@ -21,6 +21,8 @@ import org.apache.calcite.linq4j.function.Experimental; import org.apache.calcite.linq4j.function.Strict; +import org.apache.commons.xml.secure.SecureSAXParserFactory; + import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryFactory; @@ -31,14 +33,17 @@ import org.locationtech.jts.io.WKTWriter; import org.locationtech.jts.io.geojson.GeoJsonReader; import org.locationtech.jts.io.geojson.GeoJsonWriter; -import org.locationtech.jts.io.gml2.GMLReader; +import org.locationtech.jts.io.gml2.GMLHandler; import org.locationtech.jts.io.gml2.GMLWriter; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; +import java.io.StringReader; import java.util.Locale; import java.util.regex.Pattern; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; import static java.lang.Integer.parseInt; @@ -130,16 +135,31 @@ public static Geometry fromGeoJson(String geoJson) { /** * Constructs a geometry from a GML representation. * + *

The GML is parsed by a SAX parser from Apache Commons Secure XML, which + * does not fetch external DTDs or entities. + * * @param gml a GML * @return a geometry */ public static Geometry fromGml(String gml) { + final SAXParser parser; + try { + // Not namespace-aware, like JTS's GMLReader: + // GML values may use an undeclared "gml:" prefix + parser = SecureSAXParserFactory.newInstance().newSAXParser(); + } catch (ParserConfigurationException | SAXException e) { + // Tested parsers reject unsupported features eagerly in the factory, not in + // newSAXParser, so an exception here indicates a classpath problem + throw new IllegalStateException(e); + } + @SuppressWarnings("argument.type.incompatible") // delegate is documented as nullable + final GMLHandler handler = new GMLHandler(GEOMETRY_FACTORY, null); try { - GMLReader reader = new GMLReader(); - return reader.read(gml, GEOMETRY_FACTORY); - } catch (SAXException | IOException | ParserConfigurationException e) { + parser.parse(new InputSource(new StringReader(gml)), handler); + } catch (SAXException | IOException e) { throw new RuntimeException("Unable to parse GML"); } + return handler.getGeometry(); } /** diff --git a/gradle.properties b/gradle.properties index 2f9bed80d22f..9559520f9268 100644 --- a/gradle.properties +++ b/gradle.properties @@ -95,6 +95,7 @@ commons-dbcp2.version=2.11.0 commons-io.version=2.15.0 commons-math3.version=3.6.1 commons-pool2.version=2.12.0 +commons-secure-xml.version=1.0.0 commons-collections4.version=4.4 commons-text.version=1.11.0 dropwizard-metrics.version=4.0.5 diff --git a/src/main/config/forbidden-apis/signatures.txt b/src/main/config/forbidden-apis/signatures.txt index c7c95aa1f776..be50a277420e 100644 --- a/src/main/config/forbidden-apis/signatures.txt +++ b/src/main/config/forbidden-apis/signatures.txt @@ -121,3 +121,12 @@ java.net.URL#(java.net.URL, java.lang.String, java.net.URLStreamHandler) java.net.URL#(java.lang.String, java.lang.String, int, java.lang.String) java.net.URL#(java.lang.String, java.lang.String, java.lang.String) java.net.URL#(java.lang.String, java.lang.String, int, java.lang.String, java.net.URLStreamHandler) + +# Only Java 8 methods: Gradle may run on Java 8, where signatures of +# newer methods fail to parse, and code compiled for Java 8 cannot call them +@defaultMessage Use org.apache.commons.xml.secure.SecureSAXParserFactory instead +javax.xml.parsers.SAXParserFactory#newInstance(**) +org.xml.sax.helpers.XMLReaderFactory#createXMLReader(**) + +@defaultMessage GMLReader creates an unsecured SAX parser; parse with GMLHandler and SecureSAXParserFactory instead +org.locationtech.jts.io.gml2.GMLReader