From 212fdce1239a0fbcd2e4359645d11d99657bdb9b Mon Sep 17 00:00:00 2001 From: Andrea Tarocchi Date: Mon, 23 Jan 2023 17:25:48 +0100 Subject: [PATCH] Added ssl support to mongodb kamelets. --- ...mongodb-changes-stream-source.kamelet.yaml | 26 +- kamelets/mongodb-sink.kamelet.yaml | 26 +- kamelets/mongodb-source.kamelet.yaml | 26 +- library/camel-kamelets-utils/pom.xml | 7 + .../utils/mongodb/SslAwareMongoClient.java | 245 ++++++++++++++++++ ...mongodb-changes-stream-source.kamelet.yaml | 26 +- .../kamelets/mongodb-sink.kamelet.yaml | 26 +- .../kamelets/mongodb-source.kamelet.yaml | 26 +- 8 files changed, 390 insertions(+), 18 deletions(-) create mode 100644 library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/mongodb/SslAwareMongoClient.java diff --git a/kamelets/mongodb-changes-stream-source.kamelet.yaml b/kamelets/mongodb-changes-stream-source.kamelet.yaml index fa8be79c9..1fb0985e7 100644 --- a/kamelets/mongodb-changes-stream-source.kamelet.yaml +++ b/kamelets/mongodb-changes-stream-source.kamelet.yaml @@ -59,6 +59,20 @@ spec: type: string x-descriptors: - urn:camel:group:credentials + ssl: + title: Enable Ssl for Mongodb Connection + description: whether to enable ssl connection to mongodb + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' + sslValidationEnabled: + title: Enables Ssl Certificates Validation and Host name checks. + description: IMPORTANT this should be disabled only in test environment since can pose security issues. + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' database: title: MongoDB Database description: Sets the name of the MongoDB database to target. @@ -76,16 +90,22 @@ spec: beans: - name: local-mongodb type: "#class:org.apache.camel.component.mongodb.MongoDbComponent" + - name: mongo-client + type: "#class:org.apache.camel.kamelets.utils.mongodb.SslAwareMongoClient" + properties: + password: "{{?password}}" + username: "{{?username}}" + hosts: "{{hosts}}" + ssl: "{{ssl}}" + sslValidationEnabled: "{{sslValidationEnabled}}" from: uri: "{{local-mongodb}}:test" parameters: - hosts: "{{hosts}}" collection: "{{collection}}" - password: "{{?password}}" - username: "{{?username}}" database: "{{database}}" consumerType: "changeStreams" streamFilter: "{{?streamFilter}}" + mongoConnection: "#{{mongo-client}}" steps: - marshal: json: {} diff --git a/kamelets/mongodb-sink.kamelet.yaml b/kamelets/mongodb-sink.kamelet.yaml index c4f8e64b8..bd757c417 100644 --- a/kamelets/mongodb-sink.kamelet.yaml +++ b/kamelets/mongodb-sink.kamelet.yaml @@ -63,6 +63,20 @@ spec: type: string x-descriptors: - urn:camel:group:credentials + ssl: + title: Enable Ssl for Mongodb Connection + description: whether to enable ssl connection to mongodb + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' + sslValidationEnabled: + title: Enables Ssl Certificates Validation and Host name checks. + description: IMPORTANT this should be disabled only in test environment since can pose security issues. + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' database: title: MongoDB Database description: The name of the MongoDB database. @@ -90,6 +104,14 @@ spec: beans: - name: local-mongodb type: "#class:org.apache.camel.component.mongodb.MongoDbComponent" + - name: mongo-client + type: "#class:org.apache.camel.kamelets.utils.mongodb.SslAwareMongoClient" + properties: + password: "{{?password}}" + username: "{{?username}}" + hosts: "{{hosts}}" + ssl: "{{ssl}}" + sslValidationEnabled: "{{sslValidationEnabled}}" from: uri: kamelet:source steps: @@ -110,9 +132,7 @@ spec: parameters: createCollection: "{{?createCollection}}" writeConcern: "{{?writeConcern}}" - hosts: "{{hosts}}" collection: "{{collection}}" - password: "{{?password}}" - username: "{{?username}}" database: "{{database}}" operation: "insert" + mongoConnection: "#{{mongo-client}}" diff --git a/kamelets/mongodb-source.kamelet.yaml b/kamelets/mongodb-source.kamelet.yaml index 9ea2cfcc7..e928e8082 100644 --- a/kamelets/mongodb-source.kamelet.yaml +++ b/kamelets/mongodb-source.kamelet.yaml @@ -65,6 +65,20 @@ spec: type: string x-descriptors: - urn:camel:group:credentials + ssl: + title: Enable Ssl for Mongodb Connection + description: whether to enable ssl connection to mongodb + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' + sslValidationEnabled: + title: Enables Ssl Certificates Validation and Host name checks. + description: IMPORTANT this should be disabled only in test environment since can pose security issues. + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' database: title: MongoDB Database description: The name of the MongoDB database. @@ -88,16 +102,22 @@ spec: beans: - name: local-mongodb type: "#class:org.apache.camel.component.mongodb.MongoDbComponent" + - name: mongo-client + type: "#class:org.apache.camel.kamelets.utils.mongodb.SslAwareMongoClient" + properties: + password: "{{?password}}" + username: "{{?username}}" + hosts: "{{hosts}}" + ssl: "{{ssl}}" + sslValidationEnabled: "{{sslValidationEnabled}}" from: uri: "{{local-mongodb}}:test" parameters: - hosts: "{{hosts}}" collection: "{{collection}}" - password: "{{?password}}" - username: "{{?username}}" database: "{{database}}" persistentTailTracking: "{{persistentTailTracking}}" tailTrackIncreasingField: "{{?tailTrackIncreasingField}}" + mongoConnection: "#{{mongo-client}}" steps: - marshal: json: {} diff --git a/library/camel-kamelets-utils/pom.xml b/library/camel-kamelets-utils/pom.xml index 3950786f3..a5a058097 100644 --- a/library/camel-kamelets-utils/pom.xml +++ b/library/camel-kamelets-utils/pom.xml @@ -83,6 +83,13 @@ provided + + + org.apache.camel + camel-mongodb + provided + + org.junit.jupiter diff --git a/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/mongodb/SslAwareMongoClient.java b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/mongodb/SslAwareMongoClient.java new file mode 100644 index 000000000..e85ba4487 --- /dev/null +++ b/library/camel-kamelets-utils/src/main/java/org/apache/camel/kamelets/utils/mongodb/SslAwareMongoClient.java @@ -0,0 +1,245 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.kamelets.utils.mongodb; + +import com.mongodb.ClientSessionOptions; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.client.ChangeStreamIterable; +import com.mongodb.client.ClientSession; +import com.mongodb.client.ListDatabasesIterable; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.MongoIterable; +import com.mongodb.connection.ClusterDescription; +import org.apache.camel.util.function.Suppliers; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.List; +import java.util.function.Supplier; + +public class SslAwareMongoClient implements MongoClient { + private static final Logger LOG = LoggerFactory.getLogger(SslAwareMongoClient.class); + private static final TrustManager[] trustAllCerts = new TrustManager[] { + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) + throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) + throws CertificateException { + } + } + }; + private final Supplier wrappedMongoClient = Suppliers.memorize(new Supplier() { + @Override + public MongoClient get() { + String credentials = username == null ? "" : username; + + if (!credentials.equals("")) { + credentials += password == null ? "@" : ":" + password + "@"; + } + + MongoClientSettings settings = MongoClientSettings.builder() + .applyToSslSettings(builder -> { + builder.enabled(ssl); + if (!sslValidationEnabled) { + builder.invalidHostNameAllowed(true); + SSLContext sc = null; + try { + sc = SSLContext.getInstance("SSL"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Error instantiating trust all SSL context.", e); + } + try { + sc.init(null, trustAllCerts, new java.security.SecureRandom()); + } catch (KeyManagementException e) { + throw new RuntimeException("Error instantiating trust all SSL context.", e); + } + builder.context(sc); + } + }) + .applyConnectionString(new ConnectionString(String.format("mongodb://%s%s", credentials, hosts))) + .build(); + LOG.info("Connection created using provided credentials"); + return MongoClients.create(settings); + } + }); + private String hosts = null; + private String username = null; + private String password = null; + private boolean ssl = true; + + private boolean sslValidationEnabled = true; + + public MongoClient getWrappedMongoClient() { + return wrappedMongoClient.get(); + } + + @Override + public MongoDatabase getDatabase(String s) { + return getWrappedMongoClient().getDatabase(s); + } + + @Override + public ClientSession startSession() { + return getWrappedMongoClient().startSession(); + } + + @Override + public ClientSession startSession(ClientSessionOptions clientSessionOptions) { + return getWrappedMongoClient().startSession(clientSessionOptions); + } + + @Override + public void close() { + getWrappedMongoClient().close(); + } + + @Override + public MongoIterable listDatabaseNames() { + return getWrappedMongoClient().listDatabaseNames(); + } + + @Override + public MongoIterable listDatabaseNames(ClientSession clientSession) { + return getWrappedMongoClient().listDatabaseNames(clientSession); + } + + @Override + public ListDatabasesIterable listDatabases() { + return getWrappedMongoClient().listDatabases(); + } + + @Override + public ListDatabasesIterable listDatabases(ClientSession clientSession) { + return getWrappedMongoClient().listDatabases(clientSession); + } + + @Override + public ListDatabasesIterable listDatabases(Class aClass) { + return getWrappedMongoClient().listDatabases(aClass); + } + + @Override + public ListDatabasesIterable listDatabases(ClientSession clientSession, Class aClass) { + return getWrappedMongoClient().listDatabases(clientSession, aClass); + } + + @Override + public ChangeStreamIterable watch() { + return getWrappedMongoClient().watch(); + } + + @Override + public ChangeStreamIterable watch(Class aClass) { + return getWrappedMongoClient().watch(aClass); + } + + @Override + public ChangeStreamIterable watch(List list) { + return getWrappedMongoClient().watch(list); + } + + @Override + public ChangeStreamIterable watch(List list, Class aClass) { + return getWrappedMongoClient().watch(list, aClass); + } + + @Override + public ChangeStreamIterable watch(ClientSession clientSession) { + return getWrappedMongoClient().watch(clientSession); + } + + @Override + public ChangeStreamIterable watch(ClientSession clientSession, Class aClass) { + return getWrappedMongoClient().watch(clientSession, aClass); + } + + @Override + public ChangeStreamIterable watch(ClientSession clientSession, List list) { + return getWrappedMongoClient().watch(clientSession, list); + } + + @Override + public ChangeStreamIterable watch(ClientSession clientSession, List list, + Class aClass) { + return getWrappedMongoClient().watch(clientSession, list, aClass); + } + + @Override + public ClusterDescription getClusterDescription() { + return getWrappedMongoClient().getClusterDescription(); + } + + public String getHosts() { + return hosts; + } + + public void setHosts(String hosts) { + this.hosts = hosts; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public boolean isSsl() { + return ssl; + } + + public void setSsl(boolean ssl) { + this.ssl = ssl; + } + + public boolean isSslValidationEnabled() { + return sslValidationEnabled; + } + + public void setSslValidationEnabled(boolean sslValidationEnabled) { + this.sslValidationEnabled = sslValidationEnabled; + } +} diff --git a/library/camel-kamelets/src/main/resources/kamelets/mongodb-changes-stream-source.kamelet.yaml b/library/camel-kamelets/src/main/resources/kamelets/mongodb-changes-stream-source.kamelet.yaml index fa8be79c9..1fb0985e7 100644 --- a/library/camel-kamelets/src/main/resources/kamelets/mongodb-changes-stream-source.kamelet.yaml +++ b/library/camel-kamelets/src/main/resources/kamelets/mongodb-changes-stream-source.kamelet.yaml @@ -59,6 +59,20 @@ spec: type: string x-descriptors: - urn:camel:group:credentials + ssl: + title: Enable Ssl for Mongodb Connection + description: whether to enable ssl connection to mongodb + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' + sslValidationEnabled: + title: Enables Ssl Certificates Validation and Host name checks. + description: IMPORTANT this should be disabled only in test environment since can pose security issues. + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' database: title: MongoDB Database description: Sets the name of the MongoDB database to target. @@ -76,16 +90,22 @@ spec: beans: - name: local-mongodb type: "#class:org.apache.camel.component.mongodb.MongoDbComponent" + - name: mongo-client + type: "#class:org.apache.camel.kamelets.utils.mongodb.SslAwareMongoClient" + properties: + password: "{{?password}}" + username: "{{?username}}" + hosts: "{{hosts}}" + ssl: "{{ssl}}" + sslValidationEnabled: "{{sslValidationEnabled}}" from: uri: "{{local-mongodb}}:test" parameters: - hosts: "{{hosts}}" collection: "{{collection}}" - password: "{{?password}}" - username: "{{?username}}" database: "{{database}}" consumerType: "changeStreams" streamFilter: "{{?streamFilter}}" + mongoConnection: "#{{mongo-client}}" steps: - marshal: json: {} diff --git a/library/camel-kamelets/src/main/resources/kamelets/mongodb-sink.kamelet.yaml b/library/camel-kamelets/src/main/resources/kamelets/mongodb-sink.kamelet.yaml index c4f8e64b8..bd757c417 100644 --- a/library/camel-kamelets/src/main/resources/kamelets/mongodb-sink.kamelet.yaml +++ b/library/camel-kamelets/src/main/resources/kamelets/mongodb-sink.kamelet.yaml @@ -63,6 +63,20 @@ spec: type: string x-descriptors: - urn:camel:group:credentials + ssl: + title: Enable Ssl for Mongodb Connection + description: whether to enable ssl connection to mongodb + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' + sslValidationEnabled: + title: Enables Ssl Certificates Validation and Host name checks. + description: IMPORTANT this should be disabled only in test environment since can pose security issues. + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' database: title: MongoDB Database description: The name of the MongoDB database. @@ -90,6 +104,14 @@ spec: beans: - name: local-mongodb type: "#class:org.apache.camel.component.mongodb.MongoDbComponent" + - name: mongo-client + type: "#class:org.apache.camel.kamelets.utils.mongodb.SslAwareMongoClient" + properties: + password: "{{?password}}" + username: "{{?username}}" + hosts: "{{hosts}}" + ssl: "{{ssl}}" + sslValidationEnabled: "{{sslValidationEnabled}}" from: uri: kamelet:source steps: @@ -110,9 +132,7 @@ spec: parameters: createCollection: "{{?createCollection}}" writeConcern: "{{?writeConcern}}" - hosts: "{{hosts}}" collection: "{{collection}}" - password: "{{?password}}" - username: "{{?username}}" database: "{{database}}" operation: "insert" + mongoConnection: "#{{mongo-client}}" diff --git a/library/camel-kamelets/src/main/resources/kamelets/mongodb-source.kamelet.yaml b/library/camel-kamelets/src/main/resources/kamelets/mongodb-source.kamelet.yaml index 9ea2cfcc7..e928e8082 100644 --- a/library/camel-kamelets/src/main/resources/kamelets/mongodb-source.kamelet.yaml +++ b/library/camel-kamelets/src/main/resources/kamelets/mongodb-source.kamelet.yaml @@ -65,6 +65,20 @@ spec: type: string x-descriptors: - urn:camel:group:credentials + ssl: + title: Enable Ssl for Mongodb Connection + description: whether to enable ssl connection to mongodb + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' + sslValidationEnabled: + title: Enables Ssl Certificates Validation and Host name checks. + description: IMPORTANT this should be disabled only in test environment since can pose security issues. + type: boolean + default: true + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:checkbox' database: title: MongoDB Database description: The name of the MongoDB database. @@ -88,16 +102,22 @@ spec: beans: - name: local-mongodb type: "#class:org.apache.camel.component.mongodb.MongoDbComponent" + - name: mongo-client + type: "#class:org.apache.camel.kamelets.utils.mongodb.SslAwareMongoClient" + properties: + password: "{{?password}}" + username: "{{?username}}" + hosts: "{{hosts}}" + ssl: "{{ssl}}" + sslValidationEnabled: "{{sslValidationEnabled}}" from: uri: "{{local-mongodb}}:test" parameters: - hosts: "{{hosts}}" collection: "{{collection}}" - password: "{{?password}}" - username: "{{?username}}" database: "{{database}}" persistentTailTracking: "{{persistentTailTracking}}" tailTrackIncreasingField: "{{?tailTrackIncreasingField}}" + mongoConnection: "#{{mongo-client}}" steps: - marshal: json: {}