diff --git a/.gitignore b/.gitignore index 71f315d..6faa3a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /pgjdbc-REL*.tar.gz /pgjdbc-parent-poms-REL*.tar.gz /pgjdbc-v42.3.0-rc2.tar.gz +/postgresql-42.2.15-jdbc-src.tar.gz diff --git a/fix-XXE-vulnerability.patch b/fix-XXE-vulnerability.patch deleted file mode 100644 index 4b12fc2..0000000 --- a/fix-XXE-vulnerability.patch +++ /dev/null @@ -1,715 +0,0 @@ -From 0bbff72847caabbc3a7dd897a848c5bf460f4999 Mon Sep 17 00:00:00 2001 -From: Ondrej Dubaj -Date: Tue, 28 Jul 2020 14:52:25 +0200 -Subject: [PATCH] Fix for XXE vulnerability - -by defaulting to disabling external access and doc types. The -legacy insecure behavior can be restored via the new connection property xmlFactoryFactory -with a value of LEGACY_INSECURE. Alternatively, a custom class name can be specified that -implements org.postgresql.xml.PGXmlFactoryFactory and takes a no argument constructor. - -* refactor: Clean up whitespace in existing PgSQLXMLTest -* fix: Fix XXE vulnerability in PgSQLXML by disabling external access and doctypes -* fix: Add missing getter and setter for XML_FACTORY_FACTORY to BasicDataSource ---- - .../main/java/org/postgresql/PGProperty.java | 11 ++ - .../org/postgresql/core/BaseConnection.java | 9 ++ - .../postgresql/ds/common/BaseDataSource.java | 8 + - .../org/postgresql/jdbc/PgConnection.java | 40 +++++ - .../java/org/postgresql/jdbc/PgSQLXML.java | 43 +++--- - .../xml/DefaultPGXmlFactoryFactory.java | 140 ++++++++++++++++++ - .../xml/EmptyStringEntityResolver.java | 23 +++ - .../LegacyInsecurePGXmlFactoryFactory.java | 57 +++++++ - .../org/postgresql/xml/NullErrorHandler.java | 25 ++++ - .../postgresql/xml/PGXmlFactoryFactory.java | 30 ++++ - .../org/postgresql/jdbc/PgSQLXMLTest.java | 80 +++++++++- - 11 files changed, 437 insertions(+), 29 deletions(-) - create mode 100644 pgjdbc/src/main/java/org/postgresql/xml/DefaultPGXmlFactoryFactory.java - create mode 100644 pgjdbc/src/main/java/org/postgresql/xml/EmptyStringEntityResolver.java - create mode 100644 pgjdbc/src/main/java/org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java - create mode 100644 pgjdbc/src/main/java/org/postgresql/xml/NullErrorHandler.java - create mode 100644 pgjdbc/src/main/java/org/postgresql/xml/PGXmlFactoryFactory.java - -diff --git a/pgjdbc/src/main/java/org/postgresql/PGProperty.java b/pgjdbc/src/main/java/org/postgresql/PGProperty.java -index 4901889..538b244 100644 ---- a/pgjdbc/src/main/java/org/postgresql/PGProperty.java -+++ b/pgjdbc/src/main/java/org/postgresql/PGProperty.java -@@ -661,6 +661,17 @@ public enum PGProperty { - "false", - "Use SPNEGO in SSPI authentication requests"), - -+ /** -+ * Factory class to instantiate factories for XML processing. -+ * The default factory disables external entity processing. -+ * Legacy behavior with external entity processing can be enabled by specifying a value of LEGACY_INSECURE. -+ * Or specify a custom class that implements {@code org.postgresql.xml.PGXmlFactoryFactory}. -+ */ -+ XML_FACTORY_FACTORY( -+ "xmlFactoryFactory", -+ "", -+ "Factory class to instantiate factories for XML processing"), -+ - ; - - private final String name; -diff --git a/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java b/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java -index 2dbba96..56fb4b8 100644 ---- a/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java -+++ b/pgjdbc/src/main/java/org/postgresql/core/BaseConnection.java -@@ -10,6 +10,7 @@ import org.postgresql.PGProperty; - import org.postgresql.jdbc.FieldMetadata; - import org.postgresql.jdbc.TimestampUtils; - import org.postgresql.util.LruCache; -+import org.postgresql.xml.PGXmlFactoryFactory; - - import java.sql.Connection; - import java.sql.ResultSet; -@@ -212,4 +213,12 @@ public interface BaseConnection extends PGConnection, Connection { - * @see PGProperty#READ_ONLY_MODE - */ - boolean hintReadOnly(); -+ -+ /** -+ * Retrieve the factory to instantiate XML processing factories. -+ * -+ * @return The factory to use to instantiate XML processing factories -+ * @throws SQLException if the class cannot be found or instantiated. -+ */ -+ PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException; - } -diff --git a/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java b/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java -index f6e0fa7..5053b32 100644 ---- a/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java -+++ b/pgjdbc/src/main/java/org/postgresql/ds/common/BaseDataSource.java -@@ -1525,6 +1525,14 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable - } - //#endif - -+ public String getXmlFactoryFactory() { -+ return PGProperty.XML_FACTORY_FACTORY.get(properties); -+ } -+ -+ public void setXmlFactoryFactory(String xmlFactoryFactory) { -+ PGProperty.XML_FACTORY_FACTORY.set(properties, xmlFactoryFactory); -+ } -+ - /* - * Alias methods below, these are to help with ease-of-use with other database tools / frameworks - * which expect normal java bean getters / setters to exist for the property names. -diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java -index 72e9639..18d5638 100644 ---- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java -+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgConnection.java -@@ -37,6 +37,9 @@ import org.postgresql.util.PGBinaryObject; - import org.postgresql.util.PGobject; - import org.postgresql.util.PSQLException; - import org.postgresql.util.PSQLState; -+import org.postgresql.xml.DefaultPGXmlFactoryFactory; -+import org.postgresql.xml.LegacyInsecurePGXmlFactoryFactory; -+import org.postgresql.xml.PGXmlFactoryFactory; - - import java.io.IOException; - import java.sql.Array; -@@ -156,6 +159,9 @@ public class PgConnection implements BaseConnection { - - private final LruCache fieldMetadataCache; - -+ private final String xmlFactoryFactoryClass; -+ private PGXmlFactoryFactory xmlFactoryFactory; -+ - final CachedQuery borrowQuery(String sql) throws SQLException { - return queryExecutor.borrowQuery(sql); - } -@@ -311,6 +317,8 @@ public class PgConnection implements BaseConnection { - false); - - replicationConnection = PGProperty.REPLICATION.get(info) != null; -+ -+ xmlFactoryFactoryClass = PGProperty.XML_FACTORY_FACTORY.get(info); - } - - private static ReadOnlyBehavior getReadOnlyBehavior(String property) { -@@ -1823,4 +1831,36 @@ public class PgConnection implements BaseConnection { - return queryExecutor.getParameterStatus(parameterName); - } - -+ @Override -+ public PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException { -+ if (xmlFactoryFactory == null) { -+ if (xmlFactoryFactoryClass == null || xmlFactoryFactoryClass.equals("")) { -+ xmlFactoryFactory = DefaultPGXmlFactoryFactory.INSTANCE; -+ } else if (xmlFactoryFactoryClass.equals("LEGACY_INSECURE")) { -+ xmlFactoryFactory = LegacyInsecurePGXmlFactoryFactory.INSTANCE; -+ } else { -+ Class clazz; -+ try { -+ clazz = Class.forName(xmlFactoryFactoryClass); -+ } catch (ClassNotFoundException ex) { -+ throw new PSQLException( -+ GT.tr("Could not instantiate xmlFactoryFactory: {0}", xmlFactoryFactoryClass), -+ PSQLState.INVALID_PARAMETER_VALUE, ex); -+ } -+ if (!clazz.isAssignableFrom(PGXmlFactoryFactory.class)) { -+ throw new PSQLException( -+ GT.tr("Connection property xmlFactoryFactory must implement PGXmlFactoryFactory: {0}", xmlFactoryFactoryClass), -+ PSQLState.INVALID_PARAMETER_VALUE); -+ } -+ try { -+ xmlFactoryFactory = (PGXmlFactoryFactory) clazz.newInstance(); -+ } catch (Exception ex) { -+ throw new PSQLException( -+ GT.tr("Could not instantiate xmlFactoryFactory: {0}", xmlFactoryFactoryClass), -+ PSQLState.INVALID_PARAMETER_VALUE, ex); -+ } -+ } -+ } -+ return xmlFactoryFactory; -+ } - } -diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgSQLXML.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgSQLXML.java -index 919df06..c928b7b 100644 ---- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgSQLXML.java -+++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgSQLXML.java -@@ -9,10 +9,11 @@ import org.postgresql.core.BaseConnection; - import org.postgresql.util.GT; - import org.postgresql.util.PSQLException; - import org.postgresql.util.PSQLState; -+import org.postgresql.xml.DefaultPGXmlFactoryFactory; -+import org.postgresql.xml.PGXmlFactoryFactory; - --import org.xml.sax.ErrorHandler; - import org.xml.sax.InputSource; --import org.xml.sax.SAXParseException; -+import org.xml.sax.XMLReader; - - import java.io.ByteArrayInputStream; - import java.io.ByteArrayOutputStream; -@@ -27,7 +28,6 @@ import java.sql.SQLException; - import java.sql.SQLXML; - - import javax.xml.parsers.DocumentBuilder; --import javax.xml.parsers.DocumentBuilderFactory; - import javax.xml.stream.XMLInputFactory; - import javax.xml.stream.XMLOutputFactory; - import javax.xml.stream.XMLStreamException; -@@ -77,6 +77,13 @@ public class PgSQLXML implements SQLXML { - this.freed = false; - } - -+ private PGXmlFactoryFactory getXmlFactoryFactory() throws SQLException { -+ if (conn != null) { -+ return conn.getXmlFactoryFactory(); -+ } -+ return DefaultPGXmlFactoryFactory.INSTANCE; -+ } -+ - @Override - public synchronized void free() { - freed = true; -@@ -132,18 +139,17 @@ public class PgSQLXML implements SQLXML { - - try { - if (sourceClass == null || DOMSource.class.equals(sourceClass)) { -- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); -- DocumentBuilder builder = factory.newDocumentBuilder(); -- builder.setErrorHandler(new NonPrintingErrorHandler()); -+ DocumentBuilder builder = getXmlFactoryFactory().newDocumentBuilder(); - InputSource input = new InputSource(new StringReader(data)); - return (T) new DOMSource(builder.parse(input)); - } else if (SAXSource.class.equals(sourceClass)) { -+ XMLReader reader = getXmlFactoryFactory().createXMLReader(); - InputSource is = new InputSource(new StringReader(data)); -- return (T) new SAXSource(is); -+ return (T) new SAXSource(reader, is); - } else if (StreamSource.class.equals(sourceClass)) { - return (T) new StreamSource(new StringReader(data)); - } else if (StAXSource.class.equals(sourceClass)) { -- XMLInputFactory xif = XMLInputFactory.newInstance(); -+ XMLInputFactory xif = getXmlFactoryFactory().newXMLInputFactory(); - XMLStreamReader xsr = xif.createXMLStreamReader(new StringReader(data)); - return (T) new StAXSource(xsr); - } -@@ -191,8 +197,7 @@ public class PgSQLXML implements SQLXML { - return (T) domResult; - } else if (SAXResult.class.equals(resultClass)) { - try { -- SAXTransformerFactory transformerFactory = -- (SAXTransformerFactory) SAXTransformerFactory.newInstance(); -+ SAXTransformerFactory transformerFactory = getXmlFactoryFactory().newSAXTransformerFactory(); - TransformerHandler transformerHandler = transformerFactory.newTransformerHandler(); - stringWriter = new StringWriter(); - transformerHandler.setResult(new StreamResult(stringWriter)); -@@ -209,7 +214,7 @@ public class PgSQLXML implements SQLXML { - } else if (StAXResult.class.equals(resultClass)) { - stringWriter = new StringWriter(); - try { -- XMLOutputFactory xof = XMLOutputFactory.newInstance(); -+ XMLOutputFactory xof = getXmlFactoryFactory().newXMLOutputFactory(); - XMLStreamWriter xsw = xof.createXMLStreamWriter(stringWriter); - active = true; - return (T) new StAXResult(xsw); -@@ -272,7 +277,7 @@ public class PgSQLXML implements SQLXML { - // and use the identify transform to get it into a - // friendlier result format. - try { -- TransformerFactory factory = TransformerFactory.newInstance(); -+ TransformerFactory factory = getXmlFactoryFactory().newTransformerFactory(); - Transformer transformer = factory.newTransformer(); - DOMSource domSource = new DOMSource(domResult.getNode()); - StringWriter stringWriter = new StringWriter(); -@@ -298,19 +303,5 @@ public class PgSQLXML implements SQLXML { - } - initialized = true; - } -- -- // Don't clutter System.err with errors the user can't silence. -- // If something bad really happens an exception will be thrown. -- static class NonPrintingErrorHandler implements ErrorHandler { -- public void error(SAXParseException e) { -- } -- -- public void fatalError(SAXParseException e) { -- } -- -- public void warning(SAXParseException e) { -- } -- } -- - } - -diff --git a/pgjdbc/src/main/java/org/postgresql/xml/DefaultPGXmlFactoryFactory.java b/pgjdbc/src/main/java/org/postgresql/xml/DefaultPGXmlFactoryFactory.java -new file mode 100644 -index 0000000..7334935 ---- /dev/null -+++ b/pgjdbc/src/main/java/org/postgresql/xml/DefaultPGXmlFactoryFactory.java -@@ -0,0 +1,140 @@ -+/* -+ * Copyright (c) 2020, PostgreSQL Global Development Group -+ * See the LICENSE file in the project root for more information. -+ */ -+ -+package org.postgresql.xml; -+ -+import org.xml.sax.SAXException; -+import org.xml.sax.XMLReader; -+import org.xml.sax.helpers.XMLReaderFactory; -+ -+import javax.xml.XMLConstants; -+import javax.xml.parsers.DocumentBuilder; -+import javax.xml.parsers.DocumentBuilderFactory; -+import javax.xml.parsers.ParserConfigurationException; -+import javax.xml.stream.XMLInputFactory; -+import javax.xml.stream.XMLOutputFactory; -+import javax.xml.transform.TransformerFactory; -+import javax.xml.transform.sax.SAXTransformerFactory; -+ -+/** -+ * Default implementation of PGXmlFactoryFactory that configures each factory per OWASP recommendations. -+ * -+ * @see https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html -+ */ -+public class DefaultPGXmlFactoryFactory implements PGXmlFactoryFactory { -+ public static final DefaultPGXmlFactoryFactory INSTANCE = new DefaultPGXmlFactoryFactory(); -+ -+ private DefaultPGXmlFactoryFactory() { -+ } -+ -+ private DocumentBuilderFactory getDocumentBuilderFactory() { -+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); -+ setFactoryProperties(factory); -+ factory.setXIncludeAware(false); -+ factory.setExpandEntityReferences(false); -+ return factory; -+ } -+ -+ @Override -+ public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { -+ DocumentBuilder builder = getDocumentBuilderFactory().newDocumentBuilder(); -+ builder.setEntityResolver(EmptyStringEntityResolver.INSTANCE); -+ builder.setErrorHandler(NullErrorHandler.INSTANCE); -+ return builder; -+ } -+ -+ @Override -+ public TransformerFactory newTransformerFactory() { -+ TransformerFactory factory = TransformerFactory.newInstance(); -+ setFactoryProperties(factory); -+ return factory; -+ } -+ -+ @Override -+ public SAXTransformerFactory newSAXTransformerFactory() { -+ SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); -+ setFactoryProperties(factory); -+ return factory; -+ } -+ -+ @Override -+ public XMLInputFactory newXMLInputFactory() { -+ XMLInputFactory factory = XMLInputFactory.newInstance(); -+ setPropertyQuietly(factory, XMLInputFactory.SUPPORT_DTD, false); -+ setPropertyQuietly(factory, XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); -+ return factory; -+ } -+ -+ @Override -+ public XMLOutputFactory newXMLOutputFactory() { -+ XMLOutputFactory factory = XMLOutputFactory.newInstance(); -+ return factory; -+ } -+ -+ @Override -+ public XMLReader createXMLReader() throws SAXException { -+ XMLReader factory = XMLReaderFactory.createXMLReader(); -+ setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", true); -+ setFeatureQuietly(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); -+ setFeatureQuietly(factory, "http://xml.org/sax/features/external-general-entities", false); -+ setFeatureQuietly(factory, "http://xml.org/sax/features/external-parameter-entities", false); -+ factory.setErrorHandler(NullErrorHandler.INSTANCE); -+ return factory; -+ } -+ -+ private static void setFeatureQuietly(Object factory, String name, boolean value) { -+ try { -+ if (factory instanceof DocumentBuilderFactory) { -+ ((DocumentBuilderFactory) factory).setFeature(name, value); -+ } else if (factory instanceof TransformerFactory) { -+ ((TransformerFactory) factory).setFeature(name, value); -+ } else if (factory instanceof XMLReader) { -+ ((XMLReader) factory).setFeature(name, value); -+ } else { -+ throw new Error("Invalid factory class: " + factory.getClass()); -+ } -+ return; -+ } catch (Exception ignore) { -+ } -+ } -+ -+ private static void setAttributeQuietly(Object factory, String name, Object value) { -+ try { -+ if (factory instanceof DocumentBuilderFactory) { -+ ((DocumentBuilderFactory) factory).setAttribute(name, value); -+ } else if (factory instanceof TransformerFactory) { -+ ((TransformerFactory) factory).setAttribute(name, value); -+ } else { -+ throw new Error("Invalid factory class: " + factory.getClass()); -+ } -+ } catch (Exception ignore) { -+ } -+ } -+ -+ private static void setFactoryProperties(Object factory) { -+ setFeatureQuietly(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true); -+ setFeatureQuietly(factory, "http://apache.org/xml/features/disallow-doctype-decl", true); -+ setFeatureQuietly(factory, "http://apache.org/xml/features/nonvalidating/load-external-dtd", false); -+ setFeatureQuietly(factory, "http://xml.org/sax/features/external-general-entities", false); -+ setFeatureQuietly(factory, "http://xml.org/sax/features/external-parameter-entities", false); -+ // Values from XMLConstants inlined for JDK 1.6 compatibility -+ setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalDTD", ""); -+ setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalSchema", ""); -+ setAttributeQuietly(factory, "http://javax.xml.XMLConstants/property/accessExternalStylesheet", ""); -+ } -+ -+ private static void setPropertyQuietly(Object factory, String name, Object value) { -+ try { -+ if (factory instanceof XMLReader) { -+ ((XMLReader) factory).setProperty(name, value); -+ } else if (factory instanceof XMLInputFactory) { -+ ((XMLInputFactory) factory).setProperty(name, value); -+ } else { -+ throw new Error("Invalid factory class: " + factory.getClass()); -+ } -+ } catch (Exception ignore) { -+ } -+ } -+} -\ No newline at end of file -diff --git a/pgjdbc/src/main/java/org/postgresql/xml/EmptyStringEntityResolver.java b/pgjdbc/src/main/java/org/postgresql/xml/EmptyStringEntityResolver.java -new file mode 100644 -index 0000000..39227e0 ---- /dev/null -+++ b/pgjdbc/src/main/java/org/postgresql/xml/EmptyStringEntityResolver.java -@@ -0,0 +1,23 @@ -+/* -+ * Copyright (c) 2020, PostgreSQL Global Development Group -+ * See the LICENSE file in the project root for more information. -+ */ -+ -+package org.postgresql.xml; -+ -+import org.xml.sax.EntityResolver; -+import org.xml.sax.InputSource; -+import org.xml.sax.SAXException; -+ -+import java.io.IOException; -+import java.io.StringReader; -+ -+public class EmptyStringEntityResolver implements EntityResolver { -+ public static final EmptyStringEntityResolver INSTANCE = new EmptyStringEntityResolver(); -+ -+ @Override -+ public InputSource resolveEntity(String publicId, String systemId) -+ throws SAXException, IOException { -+ return new InputSource(new StringReader("")); -+ } -+} -\ No newline at end of file -diff --git a/pgjdbc/src/main/java/org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java b/pgjdbc/src/main/java/org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java -new file mode 100644 -index 0000000..ed7a66b ---- /dev/null -+++ b/pgjdbc/src/main/java/org/postgresql/xml/LegacyInsecurePGXmlFactoryFactory.java -@@ -0,0 +1,57 @@ -+/* -+ * Copyright (c) 2020, PostgreSQL Global Development Group -+ * See the LICENSE file in the project root for more information. -+ */ -+ -+package org.postgresql.xml; -+ -+import org.xml.sax.SAXException; -+import org.xml.sax.XMLReader; -+import org.xml.sax.helpers.XMLReaderFactory; -+ -+import javax.xml.parsers.DocumentBuilder; -+import javax.xml.parsers.DocumentBuilderFactory; -+import javax.xml.parsers.ParserConfigurationException; -+import javax.xml.stream.XMLInputFactory; -+import javax.xml.stream.XMLOutputFactory; -+import javax.xml.transform.TransformerFactory; -+import javax.xml.transform.sax.SAXTransformerFactory; -+ -+public class LegacyInsecurePGXmlFactoryFactory implements PGXmlFactoryFactory { -+ public static final LegacyInsecurePGXmlFactoryFactory INSTANCE = new LegacyInsecurePGXmlFactoryFactory(); -+ -+ private LegacyInsecurePGXmlFactoryFactory() { -+ } -+ -+ @Override -+ public DocumentBuilder newDocumentBuilder() throws ParserConfigurationException { -+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); -+ builder.setErrorHandler(NullErrorHandler.INSTANCE); -+ return builder; -+ } -+ -+ @Override -+ public TransformerFactory newTransformerFactory() { -+ return TransformerFactory.newInstance(); -+ } -+ -+ @Override -+ public SAXTransformerFactory newSAXTransformerFactory() { -+ return (SAXTransformerFactory) SAXTransformerFactory.newInstance(); -+ } -+ -+ @Override -+ public XMLInputFactory newXMLInputFactory() { -+ return XMLInputFactory.newInstance(); -+ } -+ -+ @Override -+ public XMLOutputFactory newXMLOutputFactory() { -+ return XMLOutputFactory.newInstance(); -+ } -+ -+ @Override -+ public XMLReader createXMLReader() throws SAXException { -+ return XMLReaderFactory.createXMLReader(); -+ } -+} -\ No newline at end of file -diff --git a/pgjdbc/src/main/java/org/postgresql/xml/NullErrorHandler.java b/pgjdbc/src/main/java/org/postgresql/xml/NullErrorHandler.java -new file mode 100644 -index 0000000..ad486c7 ---- /dev/null -+++ b/pgjdbc/src/main/java/org/postgresql/xml/NullErrorHandler.java -@@ -0,0 +1,25 @@ -+/* -+ * Copyright (c) 2020, PostgreSQL Global Development Group -+ * See the LICENSE file in the project root for more information. -+ */ -+ -+package org.postgresql.xml; -+ -+import org.xml.sax.ErrorHandler; -+import org.xml.sax.SAXParseException; -+ -+/** -+ * Error handler that silently suppresses all errors. -+ */ -+public class NullErrorHandler implements ErrorHandler { -+ public static final NullErrorHandler INSTANCE = new NullErrorHandler(); -+ -+ public void error(SAXParseException e) { -+ } -+ -+ public void fatalError(SAXParseException e) { -+ } -+ -+ public void warning(SAXParseException e) { -+ } -+} -\ No newline at end of file -diff --git a/pgjdbc/src/main/java/org/postgresql/xml/PGXmlFactoryFactory.java b/pgjdbc/src/main/java/org/postgresql/xml/PGXmlFactoryFactory.java -new file mode 100644 -index 0000000..4bb98e4 ---- /dev/null -+++ b/pgjdbc/src/main/java/org/postgresql/xml/PGXmlFactoryFactory.java -@@ -0,0 +1,30 @@ -+/* -+ * Copyright (c) 2020, PostgreSQL Global Development Group -+ * See the LICENSE file in the project root for more information. -+ */ -+ -+package org.postgresql.xml; -+ -+import org.xml.sax.SAXException; -+import org.xml.sax.XMLReader; -+ -+import javax.xml.parsers.DocumentBuilder; -+import javax.xml.parsers.ParserConfigurationException; -+import javax.xml.stream.XMLInputFactory; -+import javax.xml.stream.XMLOutputFactory; -+import javax.xml.transform.TransformerFactory; -+import javax.xml.transform.sax.SAXTransformerFactory; -+ -+public interface PGXmlFactoryFactory { -+ DocumentBuilder newDocumentBuilder() throws ParserConfigurationException; -+ -+ TransformerFactory newTransformerFactory(); -+ -+ SAXTransformerFactory newSAXTransformerFactory(); -+ -+ XMLInputFactory newXMLInputFactory(); -+ -+ XMLOutputFactory newXMLOutputFactory(); -+ -+ XMLReader createXMLReader() throws SAXException; -+} -\ No newline at end of file -diff --git a/pgjdbc/src/test/java/org/postgresql/jdbc/PgSQLXMLTest.java b/pgjdbc/src/test/java/org/postgresql/jdbc/PgSQLXMLTest.java -index 53fd56d..49e389c 100644 ---- a/pgjdbc/src/test/java/org/postgresql/jdbc/PgSQLXMLTest.java -+++ b/pgjdbc/src/test/java/org/postgresql/jdbc/PgSQLXMLTest.java -@@ -8,18 +8,36 @@ package org.postgresql.jdbc; - import static org.junit.Assert.assertEquals; - import static org.junit.Assert.assertNotNull; - import static org.junit.Assert.assertTrue; -+import static org.junit.Assert.fail; - -+import org.postgresql.PGProperty; -+import org.postgresql.core.BaseConnection; - import org.postgresql.test.TestUtil; - import org.postgresql.test.jdbc2.BaseTest4; - - import org.junit.Before; - import org.junit.Test; - -+import java.io.StringWriter; - import java.io.Writer; -+import java.sql.Connection; - import java.sql.PreparedStatement; - import java.sql.ResultSet; -+import java.sql.SQLException; - import java.sql.SQLXML; - import java.sql.Statement; -+import java.util.Properties; -+ -+import javax.xml.stream.XMLStreamException; -+import javax.xml.stream.XMLStreamReader; -+import javax.xml.transform.Source; -+import javax.xml.transform.Transformer; -+import javax.xml.transform.TransformerException; -+import javax.xml.transform.TransformerFactory; -+import javax.xml.transform.dom.DOMSource; -+import javax.xml.transform.sax.SAXSource; -+import javax.xml.transform.stax.StAXSource; -+import javax.xml.transform.stream.StreamResult; - - public class PgSQLXMLTest extends BaseTest4 { - -@@ -27,17 +45,17 @@ public class PgSQLXMLTest extends BaseTest4 { - @Before - public void setUp() throws Exception { - super.setUp(); -- TestUtil.createTempTable(con, "xmltab","x xml"); -+ TestUtil.createTempTable(con, "xmltab", "x xml"); - } - - @Test -- public void setCharacterStream() throws Exception { -+ public void setCharacterStream() throws Exception { - String exmplar = "value"; - SQLXML pgSQLXML = con.createSQLXML(); - Writer writer = pgSQLXML.setCharacterStream(); - writer.write(exmplar); - PreparedStatement preparedStatement = con.prepareStatement("insert into xmltab values (?)"); -- preparedStatement.setSQLXML(1,pgSQLXML); -+ preparedStatement.setSQLXML(1, pgSQLXML); - preparedStatement.execute(); - - Statement statement = con.createStatement(); -@@ -47,4 +65,60 @@ public class PgSQLXMLTest extends BaseTest4 { - assertNotNull(result); - assertEquals(exmplar, result.getString()); - } -+ -+ private static final String LICENSE_URL = -+ PgSQLXMLTest.class.getClassLoader().getResource("META-INF/LICENSE").toString(); -+ private static final String XXE_EXAMPLE = -+ "\n" -+ + "]>" -+ + "&xxe;"; -+ -+ @Test -+ public void testLegacyXxe() throws Exception { -+ Properties props = new Properties(); -+ props.setProperty(PGProperty.XML_FACTORY_FACTORY.getName(), "LEGACY_INSECURE"); -+ try (Connection conn = TestUtil.openDB(props)) { -+ BaseConnection baseConn = conn.unwrap(BaseConnection.class); -+ PgSQLXML xml = new PgSQLXML(baseConn, XXE_EXAMPLE); -+ xml.getSource(null); -+ } -+ } -+ -+ private static String sourceToString(Source source) throws TransformerException { -+ StringWriter sw = new StringWriter(); -+ Transformer transformer = TransformerFactory.newInstance().newTransformer(); -+ transformer.transform(source, new StreamResult(sw)); -+ return sw.toString(); -+ } -+ -+ @Test(expected = SQLException.class) -+ public void testGetSourceXxeNull() throws Exception { -+ PgSQLXML xml = new PgSQLXML(null, XXE_EXAMPLE); -+ xml.getSource(null); -+ } -+ -+ @Test(expected = SQLException.class) -+ public void testGetSourceXxeDOMSource() throws Exception { -+ PgSQLXML xml = new PgSQLXML(null, XXE_EXAMPLE); -+ xml.getSource(DOMSource.class); -+ } -+ -+ @Test(expected = TransformerException.class) -+ public void testGetSourceXxeSAXSource() throws Exception { -+ PgSQLXML xml = new PgSQLXML(null, XXE_EXAMPLE); -+ SAXSource source = xml.getSource(SAXSource.class); -+ sourceToString(source); -+ -+ } -+ -+ @Test(expected = XMLStreamException.class) -+ public void testGetSourceXxeStAXSource() throws Exception { -+ PgSQLXML xml = new PgSQLXML(null, XXE_EXAMPLE); -+ StAXSource source = xml.getSource(StAXSource.class); -+ XMLStreamReader reader = source.getXMLStreamReader(); -+ // STAX will not throw XXE error until we actually read the element -+ while (reader.hasNext()) { -+ reader.next(); -+ } -+ } - } --- -2.26.0 - diff --git a/postgresql-jdbc.spec b/postgresql-jdbc.spec index e75a51e..0210b04 100644 --- a/postgresql-jdbc.spec +++ b/postgresql-jdbc.spec @@ -43,43 +43,35 @@ %{!?runselftest:%global runselftest 1} - %global section devel %global source_path pgjdbc/src/main/java/org/postgresql -%global parent_ver 1.1.6 -%global parent_poms_builddir ./pgjdbc-parent-poms - -%global pgjdbc_mvn_options -DwaffleEnabled=false -DosgiEnabled=false \\\ - -DexcludePackageNames=org.postgresql.osgi:org.postgresql.sspi Summary: JDBC driver for PostgreSQL Name: postgresql-jdbc -Version: 42.2.12 -Release: 2%{?dist} +Version: 42.2.15 +Release: 1%{?dist} License: BSD URL: http://jdbc.postgresql.org/ -Source0: https://github.com/pgjdbc/pgjdbc/archive/REL%{version}/pgjdbc-REL%{version}.tar.gz +Source0: https://repo1.maven.org/maven2/org/postgresql/postgresql/%{version}/postgresql-%{version}-jdbc-src.tar.gz Provides: pgjdbc = %version-%release -Patch0: fix-XXE-vulnerability.patch - -# Upstream moved parent pom.xml into separate project (even though there is only -# one dependant project on it?). Let's try to not complicate packaging by -# having separate spec file for it, too. -Source1: https://github.com/pgjdbc/pgjdbc-parent-poms/archive/REL%parent_ver/pgjdbc-parent-poms-REL%{parent_ver}.tar.gz - BuildArch: noarch BuildRequires: java-devel >= 1.8 BuildRequires: maven-local +BuildRequires: maven-javadoc-plugin BuildRequires: java-comment-preprocessor BuildRequires: maven-enforcer-plugin BuildRequires: maven-plugin-bundle -BuildRequires: maven-plugin-build-helper BuildRequires: classloader-leak-test-framework BuildRequires: mvn(com.ongres.scram:client) BuildRequires: mvn(org.apache.maven.plugins:maven-clean-plugin) +BuildRequires: mvn(org.apache.maven.surefire:surefire-junit-platform) +BuildRequires: mvn(org.junit.jupiter:junit-jupiter-api) +BuildRequires: mvn(org.junit.jupiter:junit-jupiter-engine) +BuildRequires: mvn(org.junit.jupiter:junit-jupiter-params) +BuildRequires: mvn(org.junit.vintage:junit-vintage-engine) %if %runselftest BuildRequires: postgresql-contrib @@ -105,41 +97,23 @@ This package contains the API Documentation for %{name}. %prep -%setup -c -q -a 1 +%setup -c -q -mv pgjdbc-REL%version/* . -mv pgjdbc-parent-poms-REL%parent_ver pgjdbc-parent-poms - -%patch0 -p1 +mv postgresql-%{version}-jdbc-src/* . # remove any binary libs -find -name "*.jar" -or -name "*.class" | xargs rm -f +find -type f \( -name "*.jar" -or -name "*.class" \) | xargs rm -f # Build parent POMs in the same Maven call. -%pom_xpath_inject pom:modules "%parent_poms_builddir" -%pom_xpath_inject pom:parent "pgjdbc-parent-poms/pgjdbc-versions" -%pom_xpath_set pom:relativePath ../pgjdbc-parent-poms/pgjdbc-core-parent pgjdbc -%pom_xpath_remove "pom:plugin[pom:artifactId = 'maven-shade-plugin']" pgjdbc -%pom_remove_plugin :karaf-maven-plugin pgjdbc -%pom_remove_plugin :properties-maven-plugin pgjdbc-parent-poms/pgjdbc-core-parent -%pom_remove_plugin :properties-maven-plugin pgjdbc-parent-poms/pgjdbc-versions - +%pom_xpath_remove "pom:plugin[pom:artifactId = 'maven-shade-plugin']" # compat symlink: requested by dtardon (libreoffice), reverts part of # 0af97ce32de877 commit. %mvn_file org.postgresql:postgresql %{name}/postgresql %{name} postgresql -# Parent POMs should not be installed. -%mvn_package ":*{parent,versions,prevjre}*" __noinstall - # For compat reasons, make Maven artifact available under older coordinates. %mvn_alias org.postgresql:postgresql postgresql:postgresql -# Hack #1! This directory is missing for some reason, it is most probably some -# misunderstanding between maven, maven-compiler-plugin and -# java-comment-preprocessor? Not solved yet. See rhbz#1325060. -mkdir -p pgjdbc/target/generated-sources/annotations - %build # Ideally we would run "sh update-translations.sh" here, but that results @@ -174,7 +148,7 @@ EOF opts="-f" %endif -%mvn_build $opts --xmvn-javadoc -- %pgjdbc_mvn_options +%mvn_build $opts --xmvn-javadoc %install @@ -191,6 +165,9 @@ opts="-f" %changelog +* Fri Jul 24 2020 Ondrej Dubaj - 42.2.15-1 +- rebased to version 42.2.15 + * Fri Jul 24 2020 Ondrej Dubaj - 42.2.12-2 - fixed XXE vulnerability (CVE-2020-13692) - fixed javadoc build problem diff --git a/sources b/sources index 299eea8..fe04bbe 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -SHA512 (pgjdbc-REL42.2.12.tar.gz) = 60f93e02e7f6f507e2bec649c6a28c4893a03eca975e9a2755ce9fda4b5bb525adb791359efad1cfb3d0c5d0af036092552c3b6b6a61a98eb1cb93df6e5f4d3f -SHA512 (pgjdbc-parent-poms-REL1.1.6.tar.gz) = 38e34a167744476568220e979bbc4139e43537f693e5e3e969ce58dc79d5b6361e92918d7f235ae9c00786b6997ad6bd98c6b680a6e59c5219da00b8b9b5760d +SHA512 (postgresql-42.2.15-jdbc-src.tar.gz) = 7a9ce733f70638f0dee9fb04103d1f4703e9bd611fc8845e88630a5d8b24659a811fe5e9c0cafea88b98e29da9e1b6f0e5f1af15f26b5f915e40886f120b181d