From 9abdb923d13aa1a78f72e61a03ea06d9907268e9 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 26 Jun 2024 16:18:19 +0200 Subject: [PATCH 1/3] add trustStore to SSLContext for mongo client options --- .../backends/mongo/MongoBackendImpl.java | 28 ++++++++++++++++--- .../backends/mongo/MongoBackendImplTest.java | 14 +++++----- .../iot/cygnus/sinks/NGSIMongoBaseSink.java | 11 +++++++- 3 files changed, 41 insertions(+), 12 deletions(-) diff --git a/cygnus-common/src/main/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImpl.java b/cygnus-common/src/main/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImpl.java index 9d1b29b8e..7f45db7c1 100644 --- a/cygnus-common/src/main/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImpl.java +++ b/cygnus-common/src/main/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImpl.java @@ -45,6 +45,8 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; import java.security.KeyStore; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; import java.io.FileInputStream; import java.io.InputStream; import org.bson.Document; @@ -71,6 +73,8 @@ public enum Resolution { SECOND, MINUTE, HOUR, DAY, MONTH } private final Boolean sslInvalidHostNameAllowed; private final String sslKeystorePathFile; private final String sslKeystorePassword; + private final String sslTruststorePathFile; + private final String sslTruststorePassword; private final DataModel dataModel; private static final CygnusLogger LOGGER = new CygnusLogger(MongoBackendImpl.class); @@ -86,7 +90,8 @@ public enum Resolution { SECOND, MINUTE, HOUR, DAY, MONTH } public MongoBackendImpl(String mongoHosts, String mongoUsername, String mongoPassword, String mongoAuthSource, String mongoReplicaSet, DataModel dataModel, Boolean sslEnabled, Boolean sslInvalidHostNameAllowed, - String sslKeystorePathFile, String sslKeystorePassword) { + String sslKeystorePathFile, String sslKeystorePassword, + String sslTruststorePathFile, String sslTruststorePassword) { client = null; this.mongoHosts = mongoHosts; this.mongoUsername = mongoUsername; @@ -97,6 +102,8 @@ public MongoBackendImpl(String mongoHosts, String mongoUsername, String mongoPas this.sslInvalidHostNameAllowed = sslInvalidHostNameAllowed; this.sslKeystorePathFile = sslKeystorePathFile; this.sslKeystorePassword = sslKeystorePassword; + this.sslTruststorePathFile = sslTruststorePathFile; + this.sslTruststorePassword = sslTruststorePassword; this.dataModel = dataModel; } // MongoBackendImpl @@ -602,12 +609,25 @@ private MongoDatabase getDatabase(String dbName) { if (client == null) { SSLContext sslContext = null; - if (sslEnabled && (sslKeystorePathFile != null) && !sslKeystorePathFile.isEmpty()) { + + if (sslEnabled) { try { - // Init TrustManager to init SSL Context KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - try (InputStream keyStoreStream = new FileInputStream(sslKeystorePathFile)) { + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + if ((sslKeystorePathFile != null) && !sslKeystorePathFile.isEmpty()) { + try (InputStream keyStoreStream = new FileInputStream(sslKeystorePathFile)) { keyStore.load(keyStoreStream, sslKeystorePassword.toCharArray()); + } + } else { + keyStore.load(null); + } + if ((sslTruststorePathFile != null) && !sslTruststorePathFile.isEmpty()) { + try (InputStream trustStoreStream = new FileInputStream(sslTruststorePathFile)) { + trustStore.load(trustStoreStream, sslTruststorePassword.toCharArray()); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate caCert = (X509Certificate) cf.generateCertificate(trustStoreStream); + keyStore.setCertificateEntry("caCert", caCert); + } } TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); diff --git a/cygnus-common/src/test/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImplTest.java b/cygnus-common/src/test/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImplTest.java index 0625507b9..f4bb076f9 100644 --- a/cygnus-common/src/test/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImplTest.java +++ b/cygnus-common/src/test/java/com/telefonica/iot/cygnus/backends/mongo/MongoBackendImplTest.java @@ -53,7 +53,7 @@ public MongoBackendImplTest() { public void testGetRange() { System.out.println(getTestTraceHead("[MongoBackendImpl.getRange]") + "-------- Given a resolution, its related range is correctly returned"); - MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null); + MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null, null, null); try { @@ -115,7 +115,7 @@ public void testGetRange() { public void testGetOrigin() { System.out.println(getTestTraceHead("[MongoBackendImpl.getOrigin]") + "-------- Given a calendar and a resolution, its related origin is correctly returned"); - MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null); + MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null, null, null); GregorianCalendar calendar = new GregorianCalendar(2017, 4, 5, 11, 46, 13); try { @@ -198,7 +198,7 @@ public void testGetOrigin() { public void testGetOffset() { System.out.println(getTestTraceHead("[MongoBackendImpl.getOffset]") + "-------- Given a calendar and a resolution, its related offset is correctly returned"); - MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null); + MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null, null, null); GregorianCalendar calendar = new GregorianCalendar(2017, 3, 5, 11, 46, 13); // month 3 is April try { @@ -266,7 +266,7 @@ public void testBuildQueryForInsertAggregated() { String entityType = "someType"; String attrName = "someName"; GregorianCalendar calendar = new GregorianCalendar(2017, 3, 5, 11, 46, 13); // month 3 is April - MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, DataModel.DMBYSERVICEPATH, false, false, null, null); + MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, DataModel.DMBYSERVICEPATH, false, false, null, null, null, null); String queryForInsertAggregated = "{\"_id\": {\"entityId\": \"someId\", \"entityType\": \"someType\", " + "\"attrName\": \"someName\", \"origin\": {\"$date\": 1491392760000}, " + "\"resolution\": \"second\", \"range\": \"minute\"}, \"points.offset\": 13}"; @@ -353,7 +353,7 @@ public void testBuildQueryForInsertAggregated() { throw e; } // try catch - backend = new MongoBackendImpl(null, null, null, null, null, DataModel.DMBYENTITY, false, false, null, null); + backend = new MongoBackendImpl(null, null, null, null, null, DataModel.DMBYENTITY, false, false, null, null, null, null); queryForInsertAggregated = "{\"_id\": {\"attrName\": \"someName\", " + "\"origin\": {\"$date\": 1491392760000}, \"resolution\": \"second\", " @@ -457,7 +457,7 @@ public void testBuildUpdateForUpdateNumerical() { double sum2 = 200; int numSamples = 2; GregorianCalendar calendar = new GregorianCalendar(2017, 3, 5, 11, 46, 13); // month 3 is April - MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null); + MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null, null, null); String updateForUpdate = "{\"$set\": {\"attrType\": \"someType\"}, " + "\"$inc\": {\"points.$.samples\": 2, \"points.$.sum\": 20.0, \"points.$.sum2\": 200.0}, " + "\"$min\": {\"points.$.min\": 0.0}, \"$max\": {\"points.$.max\": 10.0}}"; @@ -489,7 +489,7 @@ public void testBuildUpdateForUpdateString() { String value = "someString"; int count = 2; GregorianCalendar calendar = new GregorianCalendar(2017, 3, 5, 11, 46, 13); // month 3 is April - MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null); + MongoBackendImpl backend = new MongoBackendImpl(null, null, null, null, null, null, false, false, null, null, null, null); String updateForUpdate = "{\"$set\": {\"attrType\": \"someType\"}, " + "\"$inc\": {\"points.13.samples\": 2, \"points.13.occur.someString\": 2}}"; diff --git a/cygnus-ngsi/src/main/java/com/telefonica/iot/cygnus/sinks/NGSIMongoBaseSink.java b/cygnus-ngsi/src/main/java/com/telefonica/iot/cygnus/sinks/NGSIMongoBaseSink.java index aef37af7d..bf355d64f 100644 --- a/cygnus-ngsi/src/main/java/com/telefonica/iot/cygnus/sinks/NGSIMongoBaseSink.java +++ b/cygnus-ngsi/src/main/java/com/telefonica/iot/cygnus/sinks/NGSIMongoBaseSink.java @@ -43,6 +43,8 @@ public abstract class NGSIMongoBaseSink extends NGSISink { protected Boolean sslInvalidHostNameAllowed; protected String sslKeystorePathFile; protected String sslKeystorePassword; + protected String sslTruststorePathFile; + protected String sslTruststorePassword; protected String dbPrefix; protected String collectionPrefix; protected MongoBackendImpl backend; @@ -202,6 +204,12 @@ public void configure(Context context) { sslKeystorePassword = context.getString("mongo_ssl_keystore_password", ""); LOGGER.debug("[" + this.getName() + "] Reading configuration (mongo_ssl_keystore_password=" + sslKeystorePassword + ")"); + sslTruststorePathFile = context.getString("mongo_ssl_truststore_path_file", ""); + LOGGER.debug("[" + this.getName() + "] Reading configuration (mongo_ssl_truststore_path_file=" + sslTruststorePathFile + ")"); + + sslTruststorePassword = context.getString("mongo_ssl_truststore_password", ""); + LOGGER.debug("[" + this.getName() + "] Reading configuration (mongo_ssl_truststore_password=" + sslTruststorePassword + ")"); + } // configure @Override @@ -210,7 +218,8 @@ public void start() { backend = new MongoBackendImpl(mongoHosts, mongoUsername, mongoPassword, mongoAuthSource, mongoReplicaSet, dataModel, sslEnabled, sslInvalidHostNameAllowed, - sslKeystorePathFile, sslKeystorePassword); + sslKeystorePathFile, sslKeystorePassword, + sslTruststorePathFile, sslTruststorePassword); LOGGER.debug("[" + this.getName() + "] MongoDB persistence backend created"); } catch (Exception e) { LOGGER.error("Error while creating the MongoDB persistence backend. Details=" From 482f359eca5ebd53202d67379014b6b070b24b64 Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 26 Jun 2024 16:38:27 +0200 Subject: [PATCH 2/3] update doc --- doc/cygnus-ngsi/flume_extensions_catalogue/ngsi_mongo_sink.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/cygnus-ngsi/flume_extensions_catalogue/ngsi_mongo_sink.md b/doc/cygnus-ngsi/flume_extensions_catalogue/ngsi_mongo_sink.md index d1e7fda1f..575ceb4d3 100644 --- a/doc/cygnus-ngsi/flume_extensions_catalogue/ngsi_mongo_sink.md +++ b/doc/cygnus-ngsi/flume_extensions_catalogue/ngsi_mongo_sink.md @@ -324,6 +324,8 @@ When datamodel changes Cygnus tries to recreate index (delete current and create | mongo\_ssl\_invalid\_host\_allowed | no | false | Allow invalid host name in mongo SSL connections | | mongo\_ssl\_keystore\_path\_file | no | empty | Java SSL KeyStore path file (JKS file). A JKS file could be create from a certificate file using keytool: ```keytool -importkeystore -srckeystore certificate.p12 -srcstoretype pkcs12 -destkeystore mongo_ssl_keystore.jks``` | | mongo\_ssl\_keystore\_password | no | empty | Java SSL KeyStore password for keystore file (JKS file). | +| mongo\_ssl\_truststore\_path\_file | no | empty | Java SSL TrustStore for CAs path file (JKS file). | +| mongo\_ssl\_truststore\_password | no | empty | Java SSL TrustStore password for keystore file (JKS file). | | collection\_prefix | no | sth_ | `system.` is not accepted. | | batch\_size | no | 1 | Number of events accumulated before persistence. | | batch\_timeout | no | 30 | Number of seconds the batch will be building before it is persisted as it is. | From 3356903070c235af95d9905ab09631cb829c44fa Mon Sep 17 00:00:00 2001 From: Alvaro Vega Date: Wed, 26 Jun 2024 17:00:04 +0200 Subject: [PATCH 3/3] update CNR --- CHANGES_NEXT_RELEASE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES_NEXT_RELEASE b/CHANGES_NEXT_RELEASE index 78dc1831a..1e33bbc51 100644 --- a/CHANGES_NEXT_RELEASE +++ b/CHANGES_NEXT_RELEASE @@ -1,2 +1,2 @@ -[cygnus-ngsi] [mongo-sink] Add mongo_ssl, mongo_ssl_invalid_host_allowed, mongo_ssl_keystore_path_file and mongo_ssl_keystore_password options for mongoDB connections -[cygnus-common] [mongo-backend] Use sslEnabled, sslInvalidHostNameAllowed, sslKeystorePathFile and sslKeystorePassword options for mongoDB connections +[cygnus-ngsi] [mongo-sink] Add mongo_ssl, mongo_ssl_invalid_host_allowed, mongo_ssl_keystore_path_file, mongo_ssl_keystore_password, mongo_ssl_truststore_path_file and mongo_ssl_truststore_password options for mongoDB connections +[cygnus-common] [mongo-backend] Use sslEnabled, sslInvalidHostNameAllowed, sslKeystorePathFile, sslKeystorePassword, sslTruststorePathFile and sslTruststorePassword options for mongoDB connections