From 516b0123eab8d615ea3384dc9df7a0c6c89f7cc3 Mon Sep 17 00:00:00 2001 From: gittywithexcitement Date: Tue, 18 Mar 2014 23:43:40 -0700 Subject: [PATCH 1/2] Add SSL support to mongo driver --- source/vibe/db/mongo/connection.d | 39 +++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/source/vibe/db/mongo/connection.d b/source/vibe/db/mongo/connection.d index a34d6c104c..3d0514259c 100644 --- a/source/vibe/db/mongo/connection.d +++ b/source/vibe/db/mongo/connection.d @@ -12,6 +12,7 @@ public import vibe.data.bson; import vibe.core.log; import vibe.core.net; import vibe.inet.webform; +import vibe.stream.ssl; import std.algorithm : splitter; import std.array; @@ -105,6 +106,7 @@ class MongoConnection { private { MongoClientSettings m_settings; TCPConnection m_conn; + Stream m_stream; ulong m_bytesRead; int m_msgid = 1; } @@ -134,10 +136,24 @@ class MongoConnection { * TODO: Connect to one of the specified hosts taking into consideration * options such as connect timeouts and so on. */ - try m_conn = connectTCP(m_settings.hosts[0].name, m_settings.hosts[0].port); + try { + m_conn = connectTCP(m_settings.hosts[0].name, m_settings.hosts[0].port); + if (m_settings.ssl) { + auto ctx = new SSLContext(SSLContextKind.client); + if (!m_settings.sslverifycertificate) { + ctx.peerValidationMode = SSLPeerValidationMode.none; + } + + m_stream = new SSLStream(m_conn, ctx); + } + else { + m_stream = m_conn; + } + } catch (Exception e) { throw new MongoDriverException(format("Failed to connect to MongoDB server at %s:%s.", m_settings.hosts[0].name, m_settings.hosts[0].port), __FILE__, __LINE__, e); } + m_bytesRead = 0; if(m_settings.digest != string.init) { @@ -147,6 +163,11 @@ class MongoConnection { void disconnect() { + if (m_stream) { + m_stream.finalize(); + m_stream = null; + } + if (m_conn) { m_conn.close(); m_conn = null; @@ -357,13 +378,13 @@ class MongoConnection { sendInt(response_to); sendInt(req.m_opCode); send(req.m_data.data); - m_conn.flush(); + m_stream.flush(); return id; } private void sendInt(int v) { send(toBsonData(v)); } private void sendLong(long v) { send(toBsonData(v)); } - private void send(in ubyte[] data){ m_conn.write(data); } + private void send(in ubyte[] data){ m_stream.write(data); } private int recvInt() { ubyte[int.sizeof] ret; recv(ret); return fromBsonData!int(ret); } private long recvLong() { ubyte[long.sizeof] ret; recv(ret); return fromBsonData!long(ret); } @@ -373,7 +394,7 @@ class MongoConnection { recv(bson); return Bson(Bson.Type.Object, cast(immutable)(toBsonData(len) ~ bson)); } - private void recv(ubyte[] dst) { enforce(m_conn); m_conn.read(dst); m_bytesRead += dst.length; } + private void recv(ubyte[] dst) { enforce(m_stream); m_stream.read(dst); m_bytesRead += dst.length; } private int nextMessageId() { return m_msgid++; } @@ -563,6 +584,8 @@ bool parseMongoDBUrl(out MongoClientSettings cfg, string url) case "journal": setBool(cfg.journal); break; case "connecttimeoutms": setLong(cfg.connectTimeoutMS); warnNotImplemented(); break; case "sockettimeoutms": setLong(cfg.socketTimeoutMS); warnNotImplemented(); break; + case "ssl": setBool(cfg.ssl); break; + case "sslverifycertificate": setBool(cfg.sslverifycertificate); break; case "wtimeoutms": setLong(cfg.wTimeoutMS); break; case "w": try { @@ -610,6 +633,8 @@ unittest assert(cfg.journal == false); assert(cfg.connectTimeoutMS == long.init); assert(cfg.socketTimeoutMS == long.init); + assert(cfg.ssl == bool.init); + assert(cfg.sslverifycertificate == true); cfg = MongoClientSettings.init; assert(parseMongoDBUrl(cfg, "mongodb://fred:foobar@localhost")); @@ -632,7 +657,7 @@ unittest assert(cfg.hosts[0].port == 27017); cfg = MongoClientSettings.init; - assert(parseMongoDBUrl(cfg, "mongodb://host1,host2,host3/?safe=true&w=2&wtimeoutMS=2000&slaveOk=true")); + assert(parseMongoDBUrl(cfg, "mongodb://host1,host2,host3/?safe=true&w=2&wtimeoutMS=2000&slaveOk=true&ssl=true&sslverifycertificate=false")); assert(cfg.username == ""); //assert(cfg.password == ""); assert(cfg.digest == ""); @@ -648,6 +673,8 @@ unittest assert(cfg.w == Bson(2L)); assert(cfg.wTimeoutMS == 2000); assert(cfg.defQueryFlags == QueryFlags.SlaveOk); + assert(cfg.ssl == true); + assert(cfg.sslverifycertificate == false); cfg = MongoClientSettings.init; assert(parseMongoDBUrl(cfg, @@ -769,6 +796,8 @@ class MongoClientSettings bool journal; long connectTimeoutMS; long socketTimeoutMS; + bool ssl; + bool sslverifycertificate = true; static string makeDigest(string username, string password) { From 5fb96a9c3dd82229bf013196f5198298bbc67173 Mon Sep 17 00:00:00 2001 From: gittywithexcitement Date: Tue, 18 Mar 2014 23:52:00 -0700 Subject: [PATCH 2/2] Advertise SSL support and mention nonstandard 'sslverifycertificate' --- source/vibe/db/mongo/mongo.d | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/vibe/db/mongo/mongo.d b/source/vibe/db/mongo/mongo.d index 8400377b96..15855937b7 100644 --- a/source/vibe/db/mongo/mongo.d +++ b/source/vibe/db/mongo/mongo.d @@ -27,7 +27,9 @@ import std.algorithm; safe updates, but no fsync. By specifying a URL instead, it is possible to fully customize the settings. See $(LINK http://www.mongodb.org/display/DOCS/Connections) for the complete set - of options. + of options. Note that 'sslverifycertificate' is only present in some client + bindings, including here. + Note that the returned MongoClient uses a vibe.core.connectionpool.ConnectionPool internally to create and reuse connections as necessary. Thus, the @@ -43,10 +45,15 @@ import std.algorithm; --- --- - // connectiong using the URL form with custom settings + // connecting using the URL form with custom settings auto client = connectMongoDB("mongodb://localhost/?slaveOk=true"); --- + --- + // connecting with SSL encryption enabled and verification off + auto client = connectMongoDB("mongodb://localhost/?ssl=true&sslverifycertificate=false"); + --- + Params: host = Specifies the host name or IP address of the MongoDB server. port = Can be used to specify the port of the MongoDB server if different from the default one.