Skip to content

Commit b14bfec

Browse files
authored
Merge pull request #212 from marklogic/task/fixPolarisTlsIssue
MLE-23439 - Change the TLS settings to "TLS" to permit the JVM to choose the highest possible.
2 parents 2e483fd + 68e67b4 commit b14bfec

File tree

7 files changed

+90
-53
lines changed

7 files changed

+90
-53
lines changed

config/marklogic-sink.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ ml.connection.password=
5353
# Set to 'true' to customize how an SSL connection is created. Only supported if securityContextType is 'BASIC' or 'DIGEST'.
5454
# ml.connection.enableCustomSsl=true
5555
# The TLS version to use for custom SSL
56-
# ml.connection.customSsl.tlsVersion=TLSv1.2
56+
# ml.connection.customSsl.tlsVersion=TLS
5757
# The host verification strategy for custom SSL; either 'ANY', 'COMMON', or 'STRICT'
5858
# ml.connection.customSsl.hostNameVerifier=ANY
5959
# Set this to true for 2-way SSL; defaults to 1-way SSL

config/marklogic-source.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ ml.connection.password=kafkatest
4747
# Set to 'true' to customize how an SSL connection is created. Only supported if securityContextType is 'BASIC' or 'DIGEST'.
4848
# ml.connection.enableCustomSsl=true
4949
# The TLS version to use for custom SSL
50-
# ml.connection.customSsl.tlsVersion=TLSv1.2
50+
# ml.connection.customSsl.tlsVersion=TLS
5151
# The host verification strategy for custom SSL; either 'ANY', 'COMMON', or 'STRICT'
5252
# ml.connection.customSsl.hostNameVerifier=ANY
5353
# Set this to true for 2-way SSL; defaults to 1-way SSL

docs/configuring-the-connector.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ The MarkLogic connector provides two options for configuring the usage of SSL wh
9494

9595
If a custom SSL approach is used, you can use the following properties to configure this approach:
9696

97-
- `ml.connection.customSsl.tlsVersion` = the TLS version to use for constructing an `SSLContext`. Defaults to `TLSv1.2`.
97+
- `ml.connection.customSsl.tlsVersion` = the TLS version to use for constructing an `SSLContext`. Defaults to `TLS`, permitting the JVM to use the highest version possible.
9898
- `ml.connection.customSsl.mutualAuth` = `true` to configure mutual, or "2-way", SSL authentication
9999

100100
If `ml.connection.customSsl.mutualAuth` is set to `true`, you must also configure these properties:

src/main/java/com/marklogic/kafka/connect/DefaultDatabaseClientConfigBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public DatabaseClientConfig buildDatabaseClientConfig(Map<String, Object> parsed
7878
* @param clientConfig
7979
*/
8080
private void configureSimpleSsl(DatabaseClientConfig clientConfig) {
81-
clientConfig.setSslContext(SimpleX509TrustManager.newSSLContext());
81+
clientConfig.setSslContext(SimpleX509TrustManager.newSSLContext("TLS"));
8282
clientConfig.setTrustManager(new SimpleX509TrustManager());
8383
clientConfig.setSslHostnameVerifier(DatabaseClientFactory.SSLHostnameVerifier.ANY);
8484
}

src/main/java/com/marklogic/kafka/connect/MarkLogicConfig.java

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -47,54 +47,54 @@ public static void addDefinitions(ConfigDef configDef) {
4747
GROUP, -1, ConfigDef.Width.MEDIUM, "Host")
4848
.define(CONNECTION_PORT, Type.INT, ConfigDef.NO_DEFAULT_VALUE, ConfigDef.Range.atLeast(0), Importance.HIGH,
4949
"Required; the port of a REST API app server to connect to; if using Bulk Data Services, can be a plain HTTP app server",
50-
GROUP, -1, ConfigDef.Width.MEDIUM, "Port")
51-
.define(CONNECTION_BASE_PATH, Type.STRING, null, Importance.MEDIUM,
52-
"Base path for all calls to MarkLogic; typically used when a reverse proxy is in front of MarkLogic",
53-
GROUP, -1, ConfigDef.Width.MEDIUM, "Base Path")
50+
GROUP, -1, ConfigDef.Width.MEDIUM, "Port")
51+
.define(CONNECTION_BASE_PATH, Type.STRING, null, Importance.MEDIUM,
52+
"Base path for all calls to MarkLogic; typically used when a reverse proxy is in front of MarkLogic",
53+
GROUP, -1, ConfigDef.Width.MEDIUM, "Base Path")
5454
.define(CONNECTION_SECURITY_CONTEXT_TYPE, Type.STRING, "DIGEST", CONNECTION_SECURITY_CONTEXT_TYPE_RV, Importance.HIGH,
5555
"Required; the authentication scheme used by the server defined by ml.connection.port; either 'DIGEST', 'BASIC', 'CERTIFICATE', 'KERBEROS', or 'NONE'",
56-
GROUP, -1, ConfigDef.Width.MEDIUM, "Security Context Type", CONNECTION_SECURITY_CONTEXT_TYPE_RV)
57-
.define(CONNECTION_USERNAME, Type.STRING, null, Importance.MEDIUM,
58-
"MarkLogic username for 'DIGEST' and 'BASIC' authentication",
59-
GROUP, -1, ConfigDef.Width.MEDIUM, "Username")
60-
.define(CONNECTION_PASSWORD, Type.PASSWORD, null, Importance.MEDIUM,
61-
"MarkLogic password for 'DIGEST' and 'BASIC' authentication",
62-
GROUP, -1, ConfigDef.Width.MEDIUM, "Password")
63-
.define(CONNECTION_DATABASE, Type.STRING, null, Importance.LOW,
64-
"Name of a database to connect to. If your REST API server has a content database matching that of the one that you want to write documents to, you do not need to set this.",
65-
GROUP, -1, ConfigDef.Width.MEDIUM, "Database")
66-
.define(CONNECTION_CERT_FILE, Type.STRING, null, Importance.MEDIUM,
67-
"Path to PKCS12 file for 'CERTIFICATE' authentication",
68-
GROUP, -1, ConfigDef.Width.MEDIUM, "Certificate File")
69-
.define(CONNECTION_CERT_PASSWORD, Type.PASSWORD, null, Importance.MEDIUM,
70-
"Password for PKCS12 file for 'CERTIFICATE' authentication",
71-
GROUP, -1, ConfigDef.Width.MEDIUM, "Certificate Password")
72-
.define(CONNECTION_EXTERNAL_NAME, Type.STRING, null, Importance.MEDIUM,
73-
"External name for 'KERBEROS' authentication",
74-
GROUP, -1, ConfigDef.Width.MEDIUM, "Kerberos External Name")
75-
.define(CONNECTION_CLOUD_API_KEY, Type.STRING, null, Importance.MEDIUM,
76-
"API key for connecting to MarkLogic Cloud. Should set port to 443 when connecting to MarkLogic Cloud.",
77-
GROUP, -1, ConfigDef.Width.MEDIUM, "Cloud API Key")
78-
.define(CONNECTION_TYPE, Type.STRING, "", CONNECTION_TYPE_RV, Importance.MEDIUM,
79-
"Set to 'GATEWAY' when the host identified by ml.connection.host is a load balancer. See https://docs.marklogic.com/guide/java/data-movement#id_26583 for more information.",
80-
GROUP, -1, ConfigDef.Width.MEDIUM, "Connection Type", CONNECTION_TYPE_RV)
56+
GROUP, -1, ConfigDef.Width.MEDIUM, "Security Context Type", CONNECTION_SECURITY_CONTEXT_TYPE_RV)
57+
.define(CONNECTION_USERNAME, Type.STRING, null, Importance.MEDIUM,
58+
"MarkLogic username for 'DIGEST' and 'BASIC' authentication",
59+
GROUP, -1, ConfigDef.Width.MEDIUM, "Username")
60+
.define(CONNECTION_PASSWORD, Type.PASSWORD, null, Importance.MEDIUM,
61+
"MarkLogic password for 'DIGEST' and 'BASIC' authentication",
62+
GROUP, -1, ConfigDef.Width.MEDIUM, "Password")
63+
.define(CONNECTION_DATABASE, Type.STRING, null, Importance.LOW,
64+
"Name of a database to connect to. If your REST API server has a content database matching that of the one that you want to write documents to, you do not need to set this.",
65+
GROUP, -1, ConfigDef.Width.MEDIUM, "Database")
66+
.define(CONNECTION_CERT_FILE, Type.STRING, null, Importance.MEDIUM,
67+
"Path to PKCS12 file for 'CERTIFICATE' authentication",
68+
GROUP, -1, ConfigDef.Width.MEDIUM, "Certificate File")
69+
.define(CONNECTION_CERT_PASSWORD, Type.PASSWORD, null, Importance.MEDIUM,
70+
"Password for PKCS12 file for 'CERTIFICATE' authentication",
71+
GROUP, -1, ConfigDef.Width.MEDIUM, "Certificate Password")
72+
.define(CONNECTION_EXTERNAL_NAME, Type.STRING, null, Importance.MEDIUM,
73+
"External name for 'KERBEROS' authentication",
74+
GROUP, -1, ConfigDef.Width.MEDIUM, "Kerberos External Name")
75+
.define(CONNECTION_CLOUD_API_KEY, Type.STRING, null, Importance.MEDIUM,
76+
"API key for connecting to MarkLogic Cloud. Should set port to 443 when connecting to MarkLogic Cloud.",
77+
GROUP, -1, ConfigDef.Width.MEDIUM, "Cloud API Key")
78+
.define(CONNECTION_TYPE, Type.STRING, "", CONNECTION_TYPE_RV, Importance.MEDIUM,
79+
"Set to 'GATEWAY' when the host identified by ml.connection.host is a load balancer. See https://docs.marklogic.com/guide/java/data-movement#id_26583 for more information.",
80+
GROUP, -1, ConfigDef.Width.MEDIUM, "Connection Type", CONNECTION_TYPE_RV)
8181
// Boolean fields must have a default value of null; otherwise, Confluent Platform, at least in version 7.2.1,
8282
// will show a default value of "true"
83-
.define(CONNECTION_SIMPLE_SSL, Type.BOOLEAN, null, Importance.LOW,
84-
"Set to 'true' for a simple SSL strategy that uses the JVM's default SslContext and X509TrustManager and an 'any' host verification strategy",
85-
GROUP, -1, ConfigDef.Width.MEDIUM, "Use Simple SSL")
86-
.define(ENABLE_CUSTOM_SSL, Type.BOOLEAN, null, Importance.LOW,
87-
"Set to 'true' to customize how an SSL connection is created. Only supported if securityContextType is 'BASIC' or 'DIGEST'.",
88-
GROUP, -1, ConfigDef.Width.MEDIUM, "Enable Custom SSL")
89-
.define(TLS_VERSION, Type.STRING, "TLSv1.2", Importance.LOW,
90-
"The TLS version to use for custom SSL",
91-
GROUP, -1, ConfigDef.Width.MEDIUM, "TLS Version for Custom SSL")
92-
.define(SSL_HOST_VERIFIER, Type.STRING, "ANY", SSL_HOST_VERIFIER_RV, Importance.LOW,
93-
"The host verification strategy for custom SSL; either 'ANY', 'COMMON', or 'STRICT'",
94-
GROUP, -1, ConfigDef.Width.SHORT, "SSL Hostname Verifier", SSL_HOST_VERIFIER_RV)
95-
.define(SSL_MUTUAL_AUTH, Type.BOOLEAN, null, Importance.LOW,
96-
"Set this to true for 2-way SSL; defaults to 1-way SSL",
97-
GROUP, -1, ConfigDef.Width.MEDIUM, "Use 2-way SSL");
83+
.define(CONNECTION_SIMPLE_SSL, Type.BOOLEAN, null, Importance.LOW,
84+
"Set to 'true' for a simple SSL strategy that uses the JVM's default SslContext and X509TrustManager and an 'any' host verification strategy",
85+
GROUP, -1, ConfigDef.Width.MEDIUM, "Use Simple SSL")
86+
.define(ENABLE_CUSTOM_SSL, Type.BOOLEAN, null, Importance.LOW,
87+
"Set to 'true' to customize how an SSL connection is created. Only supported if securityContextType is 'BASIC' or 'DIGEST'.",
88+
GROUP, -1, ConfigDef.Width.MEDIUM, "Enable Custom SSL")
89+
.define(TLS_VERSION, Type.STRING, "TLS", Importance.LOW,
90+
"The TLS version to use for custom SSL",
91+
GROUP, -1, ConfigDef.Width.MEDIUM, "TLS Version for Custom SSL")
92+
.define(SSL_HOST_VERIFIER, Type.STRING, "ANY", SSL_HOST_VERIFIER_RV, Importance.LOW,
93+
"The host verification strategy for custom SSL; either 'ANY', 'COMMON', or 'STRICT'",
94+
GROUP, -1, ConfigDef.Width.SHORT, "SSL Hostname Verifier", SSL_HOST_VERIFIER_RV)
95+
.define(SSL_MUTUAL_AUTH, Type.BOOLEAN, null, Importance.LOW,
96+
"Set this to true for 2-way SSL; defaults to 1-way SSL",
97+
GROUP, -1, ConfigDef.Width.MEDIUM, "Use 2-way SSL");
9898
}
9999

100100
protected MarkLogicConfig(ConfigDef definition, Map<?, ?> originals, boolean doLog) {

src/main/java/com/marklogic/kafka/connect/source/XmlPlanInvoker.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@
88
import com.marklogic.client.io.DOMHandle;
99
import com.marklogic.kafka.connect.MarkLogicConnectorException;
1010
import org.apache.kafka.connect.source.SourceRecord;
11+
import org.slf4j.Logger;
12+
import org.slf4j.LoggerFactory;
1113
import org.springframework.util.StringUtils;
1214
import org.w3c.dom.Element;
1315
import org.w3c.dom.NamedNodeMap;
1416
import org.w3c.dom.Node;
1517
import org.w3c.dom.NodeList;
1618

19+
import javax.xml.XMLConstants;
1720
import javax.xml.transform.OutputKeys;
1821
import javax.xml.transform.Transformer;
22+
import javax.xml.transform.TransformerConfigurationException;
1923
import javax.xml.transform.TransformerException;
2024
import javax.xml.transform.TransformerFactory;
2125
import javax.xml.transform.dom.DOMSource;
@@ -27,11 +31,13 @@
2731

2832
class XmlPlanInvoker extends AbstractPlanInvoker implements PlanInvoker {
2933

34+
private static final Logger logger = LoggerFactory.getLogger(XmlPlanInvoker.class);
35+
3036
private static final String TABLE_NS_URI = "http://marklogic.com/table";
3137

3238
// While a Transformer is not thread-safe and must therefore be created for each batch - though we could consider
3339
// a pooling strategy in the future - a TransformerFactory is thread-safe and can thus be reused
34-
private static final TransformerFactory transformerFactory = TransformerFactory.newInstance();
40+
private static final TransformerFactory transformerFactory = makeNewTransformerFactory();
3541

3642
public XmlPlanInvoker(DatabaseClient client, Map<String, Object> parsedConfig) {
3743
super(client, parsedConfig);
@@ -77,7 +83,7 @@ private String getKeyFromRow(Node row) {
7783
NamedNodeMap attributes = column.getAttributes();
7884
// The 'name' attribute is expected to exist; trust but verify
7985
if (attributes != null && attributes.getNamedItem("name") != null &&
80-
keyColumn.equals(attributes.getNamedItem("name").getTextContent())) {
86+
keyColumn.equals(attributes.getNamedItem("name").getTextContent())) {
8187
return column.getTextContent();
8288
}
8389
}
@@ -94,4 +100,35 @@ private String documentToString(Node newDoc, Transformer transformer) {
94100
throw new MarkLogicConnectorException("Unable to transform XML to string: " + ex.getMessage(), ex);
95101
}
96102
}
103+
104+
private static TransformerFactory makeNewTransformerFactory() {
105+
TransformerFactory factory = TransformerFactory.newInstance();
106+
// Avoids Polaris warning related to
107+
// https://cwe.mitre.org/data/definitions/611.html .
108+
// From
109+
// https://stackoverflow.com/questions/32178558/how-to-prevent-xml-external-entity-injection-on-transformerfactory
110+
// .
111+
try {
112+
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
113+
} catch (TransformerConfigurationException e) {
114+
logTransformerFactoryWarning(XMLConstants.FEATURE_SECURE_PROCESSING, e.getMessage());
115+
}
116+
try {
117+
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
118+
} catch (IllegalArgumentException e) {
119+
logTransformerFactoryWarning(XMLConstants.ACCESS_EXTERNAL_DTD, e.getMessage());
120+
}
121+
try {
122+
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
123+
} catch (IllegalArgumentException e) {
124+
logTransformerFactoryWarning(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, e.getMessage());
125+
}
126+
return factory;
127+
}
128+
129+
private static void logTransformerFactoryWarning(String xmlConstant, String errorMessage) {
130+
String baseTransformerFactoryWarningMessage = "Unable to set {} on TransformerFactory; cause: {}";
131+
logger.warn(baseTransformerFactoryWarningMessage, xmlConstant, errorMessage);
132+
}
133+
97134
}

src/test/java/com/marklogic/kafka/connect/BuildDatabaseClientConfigTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ void basicAuthenticationAndMutualSSL() {
114114
config.put(MarkLogicSinkConfig.CONNECTION_SECURITY_CONTEXT_TYPE, "basic");
115115
config.put(MarkLogicSinkConfig.CONNECTION_SIMPLE_SSL, false);
116116
config.put(MarkLogicSinkConfig.ENABLE_CUSTOM_SSL, true);
117-
config.put(MarkLogicSinkConfig.TLS_VERSION, "TLSv1.2");
117+
config.put(MarkLogicSinkConfig.TLS_VERSION, "TLS");
118118
config.put(MarkLogicSinkConfig.SSL_HOST_VERIFIER, "STRICT");
119119
config.put(MarkLogicSinkConfig.SSL_MUTUAL_AUTH, true);
120120
config.put(MarkLogicSinkConfig.CONNECTION_CERT_FILE, absolutePath);
@@ -134,7 +134,7 @@ void basicAuthenticationAndMutualSSLWithInvalidHost() {
134134
config.put(MarkLogicSinkConfig.CONNECTION_SECURITY_CONTEXT_TYPE, "basic");
135135
config.put(MarkLogicSinkConfig.CONNECTION_SIMPLE_SSL, false);
136136
config.put(MarkLogicSinkConfig.ENABLE_CUSTOM_SSL, true);
137-
config.put(MarkLogicSinkConfig.TLS_VERSION, "TLSv1.2");
137+
config.put(MarkLogicSinkConfig.TLS_VERSION, "TLS");
138138
config.put(MarkLogicSinkConfig.SSL_HOST_VERIFIER, "SOMETHING");
139139
config.put(MarkLogicSinkConfig.SSL_MUTUAL_AUTH, true);
140140
config.put(MarkLogicSinkConfig.CONNECTION_CERT_FILE, absolutePath);
@@ -154,7 +154,7 @@ void digestAuthenticationAnd1WaySSL() {
154154
config.put(MarkLogicSinkConfig.CONNECTION_SECURITY_CONTEXT_TYPE, "digest");
155155
config.put(MarkLogicSinkConfig.CONNECTION_SIMPLE_SSL, false);
156156
config.put(MarkLogicSinkConfig.ENABLE_CUSTOM_SSL, true);
157-
config.put(MarkLogicSinkConfig.TLS_VERSION, "TLSv1.2");
157+
config.put(MarkLogicSinkConfig.TLS_VERSION, "TLS");
158158
config.put(MarkLogicSinkConfig.SSL_HOST_VERIFIER, "STRICT");
159159
config.put(MarkLogicSinkConfig.SSL_MUTUAL_AUTH, false);
160160

0 commit comments

Comments
 (0)