Rebased to version 42.2.15
This commit is contained in:
parent
d23878b27a
commit
46cf776f1c
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
/pgjdbc-REL*.tar.gz
|
/pgjdbc-REL*.tar.gz
|
||||||
/pgjdbc-parent-poms-REL*.tar.gz
|
/pgjdbc-parent-poms-REL*.tar.gz
|
||||||
/pgjdbc-v42.3.0-rc2.tar.gz
|
/pgjdbc-v42.3.0-rc2.tar.gz
|
||||||
|
/postgresql-42.2.15-jdbc-src.tar.gz
|
||||||
|
@ -1,715 +0,0 @@
|
|||||||
From 0bbff72847caabbc3a7dd897a848c5bf460f4999 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Ondrej Dubaj <odubaj@redhat.com>
|
|
||||||
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<FieldMetadata.Key, FieldMetadata> 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 <a href="https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html">https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html</a>
|
|
||||||
+ */
|
|
||||||
+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 = "<x>value</x>";
|
|
||||||
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 =
|
|
||||||
+ "<!DOCTYPE foo [<!ELEMENT foo ANY >\n"
|
|
||||||
+ + "<!ENTITY xxe SYSTEM \"" + LICENSE_URL + "\">]>"
|
|
||||||
+ + "<foo>&xxe;</foo>";
|
|
||||||
+
|
|
||||||
+ @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
|
|
||||||
|
|
@ -43,47 +43,35 @@
|
|||||||
|
|
||||||
%{!?runselftest:%global runselftest 1}
|
%{!?runselftest:%global runselftest 1}
|
||||||
|
|
||||||
|
|
||||||
%global section devel
|
%global section devel
|
||||||
%global source_path pgjdbc/src/main/java/org/postgresql
|
%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
|
Summary: JDBC driver for PostgreSQL
|
||||||
Name: postgresql-jdbc
|
Name: postgresql-jdbc
|
||||||
Version: 42.2.12
|
Version: 42.2.15
|
||||||
Release: 3%{?dist}
|
Release: 1%{?dist}
|
||||||
License: BSD
|
License: BSD
|
||||||
URL: http://jdbc.postgresql.org/
|
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
|
Provides: pgjdbc = %version-%release
|
||||||
|
|
||||||
Patch0: remove-SSPIClient.patch
|
|
||||||
Patch1: 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
|
BuildArch: noarch
|
||||||
BuildRequires: java-devel >= 1.8
|
BuildRequires: java-devel >= 1.8
|
||||||
BuildRequires: maven-local
|
BuildRequires: maven-local
|
||||||
|
BuildRequires: maven-javadoc-plugin
|
||||||
BuildRequires: java-comment-preprocessor
|
BuildRequires: java-comment-preprocessor
|
||||||
BuildRequires: maven-enforcer-plugin
|
BuildRequires: maven-enforcer-plugin
|
||||||
BuildRequires: maven-plugin-bundle
|
BuildRequires: maven-plugin-bundle
|
||||||
BuildRequires: maven-plugin-build-helper
|
|
||||||
BuildRequires: classloader-leak-test-framework
|
BuildRequires: classloader-leak-test-framework
|
||||||
BuildRequires: jna
|
|
||||||
|
|
||||||
BuildRequires: mvn(com.ongres.scram:client)
|
BuildRequires: mvn(com.ongres.scram:client)
|
||||||
BuildRequires: mvn(org.apache.maven.plugins:maven-clean-plugin)
|
BuildRequires: mvn(org.apache.maven.plugins:maven-clean-plugin)
|
||||||
BuildRequires: mvn(org.osgi:osgi.cmpn)
|
BuildRequires: mvn(org.apache.maven.surefire:surefire-junit-platform)
|
||||||
BuildRequires: mvn(org.osgi:osgi.core)
|
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
|
%if %runselftest
|
||||||
BuildRequires: postgresql-contrib
|
BuildRequires: postgresql-contrib
|
||||||
@ -109,47 +97,23 @@ This package contains the API Documentation for %{name}.
|
|||||||
|
|
||||||
|
|
||||||
%prep
|
%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
|
|
||||||
%patch1 -p1
|
|
||||||
|
|
||||||
|
mv postgresql-%{version}-jdbc-src/* .
|
||||||
|
|
||||||
# remove any binary libs
|
# 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.
|
# Build parent POMs in the same Maven call.
|
||||||
%pom_xpath_inject pom:modules "<module>%parent_poms_builddir</module>"
|
%pom_xpath_remove "pom:plugin[pom:artifactId = 'maven-shade-plugin']"
|
||||||
%pom_xpath_inject pom:parent "<relativePath>pgjdbc-parent-poms/pgjdbc-versions</relativePath>"
|
|
||||||
%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_add_dep org.osgi:osgi.cmpn
|
|
||||||
%pom_add_dep org.osgi:osgi.core
|
|
||||||
%pom_add_dep net.java.dev.jna:jna
|
|
||||||
|
|
||||||
|
|
||||||
# compat symlink: requested by dtardon (libreoffice), reverts part of
|
# compat symlink: requested by dtardon (libreoffice), reverts part of
|
||||||
# 0af97ce32de877 commit.
|
# 0af97ce32de877 commit.
|
||||||
%mvn_file org.postgresql:postgresql %{name}/postgresql %{name} postgresql
|
%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.
|
# For compat reasons, make Maven artifact available under older coordinates.
|
||||||
%mvn_alias org.postgresql:postgresql postgresql:postgresql
|
%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
|
%build
|
||||||
# Ideally we would run "sh update-translations.sh" here, but that results
|
# Ideally we would run "sh update-translations.sh" here, but that results
|
||||||
@ -184,7 +148,7 @@ EOF
|
|||||||
opts="-f"
|
opts="-f"
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%mvn_build $opts --xmvn-javadoc -- %pgjdbc_mvn_options
|
%mvn_build $opts --xmvn-javadoc
|
||||||
|
|
||||||
|
|
||||||
%install
|
%install
|
||||||
@ -201,6 +165,9 @@ opts="-f"
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Fri Jul 24 2020 Ondrej Dubaj <odubaj@redhat.com> - 42.2.15-1
|
||||||
|
- rebased to version 42.2.15
|
||||||
|
|
||||||
* Fri Jul 24 2020 Ondrej Dubaj <odubaj@redhat.com> - 42.2.12-3
|
* Fri Jul 24 2020 Ondrej Dubaj <odubaj@redhat.com> - 42.2.12-3
|
||||||
- fixed javadoc build problem + added missing dependencies
|
- fixed javadoc build problem + added missing dependencies
|
||||||
- remove SSPIClient for windows API
|
- remove SSPIClient for windows API
|
||||||
|
@ -1,248 +0,0 @@
|
|||||||
diff --git a/pgjdbc/src/main/java/org/postgresql/sspi/SSPIClient.java b/pgjdbc/src/main/java/org/postgresql/sspi/SSPIClient.java
|
|
||||||
deleted file mode 100644
|
|
||||||
index b6c47b8..0000000
|
|
||||||
--- a/pgjdbc/src/main/java/org/postgresql/sspi/SSPIClient.java
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1,242 +0,0 @@
|
|
||||||
-/*
|
|
||||||
- * Copyright (c) 2003, PostgreSQL Global Development Group
|
|
||||||
- * See the LICENSE file in the project root for more information.
|
|
||||||
- */
|
|
||||||
-// Copyright (c) 2004, Open Cloud Limited.
|
|
||||||
-
|
|
||||||
-package org.postgresql.sspi;
|
|
||||||
-
|
|
||||||
-import org.postgresql.core.PGStream;
|
|
||||||
-import org.postgresql.util.HostSpec;
|
|
||||||
-import org.postgresql.util.PSQLException;
|
|
||||||
-import org.postgresql.util.PSQLState;
|
|
||||||
-
|
|
||||||
-import com.sun.jna.LastErrorException;
|
|
||||||
-import com.sun.jna.Platform;
|
|
||||||
-import com.sun.jna.platform.win32.Sspi;
|
|
||||||
-import com.sun.jna.platform.win32.Sspi.SecBufferDesc;
|
|
||||||
-import com.sun.jna.platform.win32.Win32Exception;
|
|
||||||
-import waffle.windows.auth.IWindowsCredentialsHandle;
|
|
||||||
-import waffle.windows.auth.impl.WindowsCredentialsHandleImpl;
|
|
||||||
-import waffle.windows.auth.impl.WindowsSecurityContextImpl;
|
|
||||||
-
|
|
||||||
-import java.io.IOException;
|
|
||||||
-import java.sql.SQLException;
|
|
||||||
-import java.util.logging.Level;
|
|
||||||
-import java.util.logging.Logger;
|
|
||||||
-
|
|
||||||
-/**
|
|
||||||
- * <p>Use Waffle-JNI to support SSPI authentication when PgJDBC is running on a Windows client and
|
|
||||||
- * talking to a Windows server.</p>
|
|
||||||
- *
|
|
||||||
- * <p>SSPI is not supported on a non-Windows client.</p>
|
|
||||||
- *
|
|
||||||
- * @author craig
|
|
||||||
- */
|
|
||||||
-public class SSPIClient implements ISSPIClient {
|
|
||||||
-
|
|
||||||
- public static final String SSPI_DEFAULT_SPN_SERVICE_CLASS = "POSTGRES";
|
|
||||||
-
|
|
||||||
- private static final Logger LOGGER = Logger.getLogger(SSPIClient.class.getName());
|
|
||||||
- private final PGStream pgStream;
|
|
||||||
- private final String spnServiceClass;
|
|
||||||
- private final boolean enableNegotiate;
|
|
||||||
-
|
|
||||||
- private IWindowsCredentialsHandle clientCredentials;
|
|
||||||
- private WindowsSecurityContextImpl sspiContext;
|
|
||||||
- private String targetName;
|
|
||||||
-
|
|
||||||
- /**
|
|
||||||
- * <p>Instantiate an SSPIClient for authentication of a connection.</p>
|
|
||||||
- *
|
|
||||||
- * <p>SSPIClient is not re-usable across connections.</p>
|
|
||||||
- *
|
|
||||||
- * <p>It is safe to instantiate SSPIClient even if Waffle and JNA are missing or on non-Windows
|
|
||||||
- * platforms, however you may not call any methods other than isSSPISupported().</p>
|
|
||||||
- *
|
|
||||||
- * @param pgStream PostgreSQL connection stream
|
|
||||||
- * @param spnServiceClass SSPI SPN service class, defaults to POSTGRES if null
|
|
||||||
- * @param enableNegotiate enable negotiate
|
|
||||||
- */
|
|
||||||
- public SSPIClient(PGStream pgStream, String spnServiceClass, boolean enableNegotiate) {
|
|
||||||
- this.pgStream = pgStream;
|
|
||||||
-
|
|
||||||
- if (spnServiceClass == null || spnServiceClass.isEmpty()) {
|
|
||||||
- spnServiceClass = SSPI_DEFAULT_SPN_SERVICE_CLASS;
|
|
||||||
- }
|
|
||||||
- this.spnServiceClass = spnServiceClass;
|
|
||||||
-
|
|
||||||
- /* If we're forcing Kerberos (no spnego), disable SSPI negotiation */
|
|
||||||
- this.enableNegotiate = enableNegotiate;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /**
|
|
||||||
- * Test whether we can attempt SSPI authentication. If false, do not attempt to call any other
|
|
||||||
- * SSPIClient methods.
|
|
||||||
- *
|
|
||||||
- * @return true if it's safe to attempt SSPI authentication
|
|
||||||
- */
|
|
||||||
- @Override
|
|
||||||
- public boolean isSSPISupported() {
|
|
||||||
- try {
|
|
||||||
- /*
|
|
||||||
- * SSPI is windows-only. Attempt to use JNA to identify the platform. If Waffle is missing we
|
|
||||||
- * won't have JNA and this will throw a NoClassDefFoundError.
|
|
||||||
- */
|
|
||||||
- if (!Platform.isWindows()) {
|
|
||||||
- LOGGER.log(Level.FINE, "SSPI not supported: non-Windows host");
|
|
||||||
- return false;
|
|
||||||
- }
|
|
||||||
- /* Waffle must be on the CLASSPATH */
|
|
||||||
- Class.forName("waffle.windows.auth.impl.WindowsSecurityContextImpl");
|
|
||||||
- return true;
|
|
||||||
- } catch (NoClassDefFoundError ex) {
|
|
||||||
- LOGGER.log(Level.WARNING, "SSPI unavailable (no Waffle/JNA libraries?)", ex);
|
|
||||||
- return false;
|
|
||||||
- } catch (ClassNotFoundException ex) {
|
|
||||||
- LOGGER.log(Level.WARNING, "SSPI unavailable (no Waffle/JNA libraries?)", ex);
|
|
||||||
- return false;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- private String makeSPN() throws PSQLException {
|
|
||||||
- final HostSpec hs = pgStream.getHostSpec();
|
|
||||||
-
|
|
||||||
- try {
|
|
||||||
- /*
|
|
||||||
- The GSSAPI implementation does not use the port in the service name.
|
|
||||||
- Force the port number to 0
|
|
||||||
- Fixes issue 1482
|
|
||||||
- */
|
|
||||||
- return NTDSAPIWrapper.instance.DsMakeSpn(spnServiceClass, hs.getHost(), null,
|
|
||||||
- (short) 0, null);
|
|
||||||
- } catch (LastErrorException ex) {
|
|
||||||
- throw new PSQLException("SSPI setup failed to determine SPN",
|
|
||||||
- PSQLState.CONNECTION_UNABLE_TO_CONNECT, ex);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /**
|
|
||||||
- * Respond to an authentication request from the back-end for SSPI authentication (AUTH_REQ_SSPI).
|
|
||||||
- *
|
|
||||||
- * @throws SQLException on SSPI authentication handshake failure
|
|
||||||
- * @throws IOException on network I/O issues
|
|
||||||
- */
|
|
||||||
- @Override
|
|
||||||
- public void startSSPI() throws SQLException, IOException {
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * We usually use SSPI negotiation (spnego), but it's disabled if the client asked for GSSPI and
|
|
||||||
- * usespngo isn't explicitly turned on.
|
|
||||||
- */
|
|
||||||
- final String securityPackage = enableNegotiate ? "negotiate" : "kerberos";
|
|
||||||
-
|
|
||||||
- LOGGER.log(Level.FINEST, "Beginning SSPI/Kerberos negotiation with SSPI package: {0}", securityPackage);
|
|
||||||
-
|
|
||||||
- try {
|
|
||||||
- /*
|
|
||||||
- * Acquire a handle for the local Windows login credentials for the current user
|
|
||||||
- *
|
|
||||||
- * See AcquireCredentialsHandle
|
|
||||||
- * (http://msdn.microsoft.com/en-us/library/windows/desktop/aa374712%28v=vs.85%29.aspx)
|
|
||||||
- *
|
|
||||||
- * This corresponds to pg_SSPI_startup in libpq/fe-auth.c .
|
|
||||||
- */
|
|
||||||
- try {
|
|
||||||
- clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
|
|
||||||
- clientCredentials.initialize();
|
|
||||||
- } catch (Win32Exception ex) {
|
|
||||||
- throw new PSQLException("Could not obtain local Windows credentials for SSPI",
|
|
||||||
- PSQLState.CONNECTION_UNABLE_TO_CONNECT /* TODO: Should be authentication error */, ex);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- try {
|
|
||||||
- targetName = makeSPN();
|
|
||||||
-
|
|
||||||
- LOGGER.log(Level.FINEST, "SSPI target name: {0}", targetName);
|
|
||||||
-
|
|
||||||
- sspiContext = new WindowsSecurityContextImpl();
|
|
||||||
- sspiContext.setPrincipalName(targetName);
|
|
||||||
- sspiContext.setCredentialsHandle(clientCredentials);
|
|
||||||
- sspiContext.setSecurityPackage(securityPackage);
|
|
||||||
- sspiContext.initialize(null, null, targetName);
|
|
||||||
- } catch (Win32Exception ex) {
|
|
||||||
- throw new PSQLException("Could not initialize SSPI security context",
|
|
||||||
- PSQLState.CONNECTION_UNABLE_TO_CONNECT /* TODO: Should be auth error */, ex);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- sendSSPIResponse(sspiContext.getToken());
|
|
||||||
- LOGGER.log(Level.FINEST, "Sent first SSPI negotiation message");
|
|
||||||
- } catch (NoClassDefFoundError ex) {
|
|
||||||
- throw new PSQLException(
|
|
||||||
- "SSPI cannot be used, Waffle or its dependencies are missing from the classpath",
|
|
||||||
- PSQLState.NOT_IMPLEMENTED, ex);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /**
|
|
||||||
- * Continue an existing authentication conversation with the back-end in resonse to an
|
|
||||||
- * authentication request of type AUTH_REQ_GSS_CONT.
|
|
||||||
- *
|
|
||||||
- * @param msgLength Length of message to read, excluding length word and message type word
|
|
||||||
- * @throws SQLException if something wrong happens
|
|
||||||
- * @throws IOException if something wrong happens
|
|
||||||
- */
|
|
||||||
- @Override
|
|
||||||
- public void continueSSPI(int msgLength) throws SQLException, IOException {
|
|
||||||
-
|
|
||||||
- if (sspiContext == null) {
|
|
||||||
- throw new IllegalStateException("Cannot continue SSPI authentication that we didn't begin");
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- LOGGER.log(Level.FINEST, "Continuing SSPI negotiation");
|
|
||||||
-
|
|
||||||
- /* Read the response token from the server */
|
|
||||||
- byte[] receivedToken = pgStream.receive(msgLength);
|
|
||||||
-
|
|
||||||
- SecBufferDesc continueToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, receivedToken);
|
|
||||||
-
|
|
||||||
- sspiContext.initialize(sspiContext.getHandle(), continueToken, targetName);
|
|
||||||
-
|
|
||||||
- /*
|
|
||||||
- * Now send the response token. If negotiation is complete there may be zero bytes to send, in
|
|
||||||
- * which case we shouldn't send a reply as the server is not expecting one; see fe-auth.c in
|
|
||||||
- * libpq for details.
|
|
||||||
- */
|
|
||||||
- byte[] responseToken = sspiContext.getToken();
|
|
||||||
- if (responseToken.length > 0) {
|
|
||||||
- sendSSPIResponse(responseToken);
|
|
||||||
- LOGGER.log(Level.FINEST, "Sent SSPI negotiation continuation message");
|
|
||||||
- } else {
|
|
||||||
- LOGGER.log(Level.FINEST, "SSPI authentication complete, no reply required");
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- private void sendSSPIResponse(byte[] outToken) throws IOException {
|
|
||||||
- /*
|
|
||||||
- * The sspiContext now contains a token we can send to the server to start the handshake. Send a
|
|
||||||
- * 'password' message containing the required data; the server knows we're doing SSPI
|
|
||||||
- * negotiation and will deal with it appropriately.
|
|
||||||
- */
|
|
||||||
- pgStream.sendChar('p');
|
|
||||||
- pgStream.sendInteger4(4 + outToken.length);
|
|
||||||
- pgStream.send(outToken);
|
|
||||||
- pgStream.flush();
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /**
|
|
||||||
- * Clean up native win32 resources after completion or failure of SSPI authentication. This
|
|
||||||
- * SSPIClient instance becomes unusable after disposal.
|
|
||||||
- */
|
|
||||||
- @Override
|
|
||||||
- public void dispose() {
|
|
||||||
- if (sspiContext != null) {
|
|
||||||
- sspiContext.dispose();
|
|
||||||
- sspiContext = null;
|
|
||||||
- }
|
|
||||||
- if (clientCredentials != null) {
|
|
||||||
- clientCredentials.dispose();
|
|
||||||
- clientCredentials = null;
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-}
|
|
3
sources
3
sources
@ -1,2 +1 @@
|
|||||||
SHA512 (pgjdbc-REL42.2.12.tar.gz) = 60f93e02e7f6f507e2bec649c6a28c4893a03eca975e9a2755ce9fda4b5bb525adb791359efad1cfb3d0c5d0af036092552c3b6b6a61a98eb1cb93df6e5f4d3f
|
SHA512 (postgresql-42.2.15-jdbc-src.tar.gz) = 7a9ce733f70638f0dee9fb04103d1f4703e9bd611fc8845e88630a5d8b24659a811fe5e9c0cafea88b98e29da9e1b6f0e5f1af15f26b5f915e40886f120b181d
|
||||||
SHA512 (pgjdbc-parent-poms-REL1.1.6.tar.gz) = 38e34a167744476568220e979bbc4139e43537f693e5e3e969ce58dc79d5b6361e92918d7f235ae9c00786b6997ad6bd98c6b680a6e59c5219da00b8b9b5760d
|
|
||||||
|
Loading…
Reference in New Issue
Block a user