From 93f11e168a7ed417e9936d891af51af5e8079543 Mon Sep 17 00:00:00 2001 From: "Ricketts, M (Mike)" Date: Tue, 19 Nov 2019 13:20:24 +0000 Subject: [PATCH 1/2] Add support for connecting to MongoDB using SSL --- doc/INSTALL.md | 4 +- server/build.gradle | 4 ++ server/config/bootstrap.properties | 21 ++++++-- server/config/server.xml | 11 ++-- .../ibm/ws/lars/rest/mongo/MongoProducer.java | 54 ++++++++++++++++--- 5 files changed, 78 insertions(+), 16 deletions(-) diff --git a/doc/INSTALL.md b/doc/INSTALL.md index 16d7340..84c55ec 100644 --- a/doc/INSTALL.md +++ b/doc/INSTALL.md @@ -52,8 +52,8 @@ authorization for applications on Liberty, see [Configuring authorization for ap ### MongoDB configuration -If your MongoDB instance uses authentication or if other parameters, such as the MongoDB port, -are non-default then you may need to customize the properties in `bootstrap.properties`. +If your MongoDB instance uses authentication or SSL, or if other parameters such as the MongoDB port +are non-default then you will need to customize the properties in `bootstrap.properties`. ## Starting the server diff --git a/server/build.gradle b/server/build.gradle index 1b20363..9769797 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -56,6 +56,9 @@ def requiredIbmJars = [ def requiredThirdPartyJars = [ 'com.ibm.websphere.appserver.thirdparty.jaxrs_*.jar'] +def requiredLibs = [ + 'com.ibm.ws.ssl*.jar'] + ext { serverName = archivesBaseName testServerName = 'testServer' @@ -86,6 +89,7 @@ dependencies { providedCompile fileTree(dir: "${libertyRoot}/dev/api/spec", include: requiredSpecJars) providedCompile fileTree(dir: "${libertyRoot}/dev/api/ibm", include: requiredIbmJars) providedCompile fileTree(dir: "${libertyRoot}/dev/api/third-party", include: requiredThirdPartyJars) + providedCompile fileTree(dir: "${libertyRoot}/lib", include: requiredLibs) providedCompile group:'com.google.code.findbugs', name:'annotations', version: '3.0.+' testCompile group:'junit', name:'junit', version:junit_version diff --git a/server/config/bootstrap.properties b/server/config/bootstrap.properties index 502bbe7..52b1886 100644 --- a/server/config/bootstrap.properties +++ b/server/config/bootstrap.properties @@ -1,18 +1,31 @@ -# For a single mongodb server: +#### Basic configuration #### +# For a single MongoDB server: #lars.mongo.hostname=localhost #lars.mongo.port=27017 -# For a mongodb cluster: +# Or for a MongoDB cluster add as many hostname/port pairs as needed: #lars.mongo.hostname0= #lars.mongo.port0= #lars.mongo.hostname1= #lars.mongo.port1= +# Name of the database (will be created if needed) lars.mongo.dbname=larsDB +# Use slightly safer write concern than the default +lars.mongo.writeConcern=JOURNALED + +#### Authentication #### # If authentication is required: #lars.mongo.user= #lars.mongo.pass.encoded= +# If a different db is used for authentication: +#lars.mongo.authdb=admin -# Use slightly safer write concern than the default -lars.mongo.writeConcern=JOURNALED +#### SSL Configuration #### +# To connect to MongoDB using SSL (or TLS) +#lars.mongo.sslEnabled=true +# Use this to specify custom SSL settings, for example if a trust store +# is required. The value of this property refers to an entry in +# the server.xml +#lars.mongo.sslConfig=mongoSSLConfig diff --git a/server/config/server.xml b/server/config/server.xml index 716a272..e4c24c5 100644 --- a/server/config/server.xml +++ b/server/config/server.xml @@ -49,13 +49,17 @@ limitations under the License. - + + + + @@ -76,4 +80,5 @@ limitations under the License. --> + diff --git a/server/src/main/java/com/ibm/ws/lars/rest/mongo/MongoProducer.java b/server/src/main/java/com/ibm/ws/lars/rest/mongo/MongoProducer.java index 25d4672..ec2b315 100644 --- a/server/src/main/java/com/ibm/ws/lars/rest/mongo/MongoProducer.java +++ b/server/src/main/java/com/ibm/ws/lars/rest/mongo/MongoProducer.java @@ -15,6 +15,7 @@ import javax.enterprise.inject.Produces; import javax.annotation.PostConstruct; import javax.inject.Inject; +import javax.net.ssl.SSLContext; import com.ibm.websphere.crypto.PasswordUtil; import com.mongodb.MongoClient; @@ -39,9 +40,12 @@ public class MongoProducer { private static final Logger logger = Logger.getLogger(MongoProducer.class.getCanonicalName()); private String dbName = null; + private String authDbName = null; private String user = null; private String encodedPass = null; private String requestedWriteConcern = null; + private boolean sslEnabled = false; + private String sslConfig = null; private ArrayList servers = new ArrayList(2); @PostConstruct @@ -54,10 +58,22 @@ private void readConfig() { // user and password (optional - if not set, use unauthenticated access) user = sysprops.getProperty("lars.mongo.user"); encodedPass = sysprops.getProperty("lars.mongo.pass.encoded"); + authDbName = sysprops.getProperty("lars.mongo.authdb"); + if(authDbName == null) { + authDbName = dbName; + } // writeConcern (optional - if not set use the default "ACKNOWLEDGED") requestedWriteConcern = sysprops.getProperty("lars.mongo.writeConcern"); + // sslEnabled (optional - if not set, assume false) + if("true".equalsIgnoreCase(sysprops.getProperty("lars.mongo.sslEnabled","false"))) { + sslEnabled = true; + } + + // sslConfig (optional, only used if ssl is enabled) + sslConfig = sysprops.getProperty("lars.mongo.sslConfig"); + // look for all lars.mongo.hostname* properties, in alphabetical order Enumeration keysEnum = sysprops.keys(); Vector keyList = new Vector(); @@ -89,7 +105,9 @@ private void readConfig() { @Produces public MongoClient createMongo() { - MongoClientOptions opts; + MongoClientOptions.Builder builder = MongoClientOptions.builder(); + + // set the WriteConcern, if specified if(requestedWriteConcern != null) { WriteConcern wc; switch(requestedWriteConcern) @@ -131,26 +149,48 @@ public MongoClient createMongo() { wc = WriteConcern.ACKNOWLEDGED; logger.warning("No WriteConcern named " + requestedWriteConcern + " found. Using default WriteConcern of ACKNOWLEDGED."); } - opts = new MongoClientOptions.Builder().writeConcern(wc).build(); + builder = builder.writeConcern(wc); logger.info("createMongo: using write concern " + requestedWriteConcern); } else { - opts = new MongoClientOptions.Builder().build(); logger.info("createMongo: using default write concern"); } - if(encodedPass == null) { - logger.info("createMongo: connecting to database "+dbName+" using unauthenticated access"); + // Configure SSL + if(sslEnabled) { + try { + SSLContext sslContext; + if(sslConfig == null) { + sslContext = SSLContext.getDefault(); + } else { + sslContext = com.ibm.websphere.ssl.JSSEHelper.getInstance().getSSLContext(sslConfig, Collections.emptyMap(), null); + } + logger.info("createMongo: SSL enabled"); + builder = builder.sslEnabled(sslEnabled).sslContext(sslContext); + } catch(com.ibm.websphere.ssl.SSLException ex) { + logger.severe("createMongo: Failed to initialize SSL: "+ex.getMessage()); + return null; + } catch(java.security.NoSuchAlgorithmException ex) { + logger.severe("createMongo: Failed to initialize SSL: "+ex.getMessage()); + return null; + } + } + MongoClientOptions opts = builder.build(); + + // Configure credentials, and connect + if(encodedPass == null) { + logger.info("createMongo: connecting using unauthenticated access"); return new MongoClient(servers, opts); } else { String password = PasswordUtil.passwordDecode(encodedPass); - MongoCredential creds = MongoCredential.createCredential(user, dbName, password.toCharArray()); - logger.info("createMongo: connecting to database "+dbName+" as user "+user); + MongoCredential creds = MongoCredential.createCredential(user, authDbName, password.toCharArray()); + logger.info("createMongo: connecting using user "+user+" and authentication database "+authDbName); return new MongoClient(servers, creds, opts); } } @Produces public DB createDB(MongoClient client) { + logger.info("createMongo: connecting to database "+dbName); return client.getDB(dbName); } From 29d1f17a62c013fec2446a552b8c60c93bcc61a4 Mon Sep 17 00:00:00 2001 From: "Ricketts, M (Mike)" Date: Tue, 19 Nov 2019 13:46:01 +0000 Subject: [PATCH 2/2] Get SSL classes from API jar instead of lib --- server/build.gradle | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/server/build.gradle b/server/build.gradle index 9769797..02986f1 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -51,14 +51,12 @@ def requiredSpecJars = [ 'com.ibm.*.javaee.annotation.1.1_*.jar'] def requiredIbmJars = [ - 'com.ibm.*.passwordUtil_*.jar'] + 'com.ibm.*.passwordUtil_*.jar', + 'com.ibm.*.ssl_*.jar'] def requiredThirdPartyJars = [ 'com.ibm.websphere.appserver.thirdparty.jaxrs_*.jar'] -def requiredLibs = [ - 'com.ibm.ws.ssl*.jar'] - ext { serverName = archivesBaseName testServerName = 'testServer' @@ -89,7 +87,6 @@ dependencies { providedCompile fileTree(dir: "${libertyRoot}/dev/api/spec", include: requiredSpecJars) providedCompile fileTree(dir: "${libertyRoot}/dev/api/ibm", include: requiredIbmJars) providedCompile fileTree(dir: "${libertyRoot}/dev/api/third-party", include: requiredThirdPartyJars) - providedCompile fileTree(dir: "${libertyRoot}/lib", include: requiredLibs) providedCompile group:'com.google.code.findbugs', name:'annotations', version: '3.0.+' testCompile group:'junit', name:'junit', version:junit_version