Skip to content

Commit

Permalink
Merge pull request vibe-d#587 from gittywithexcitement/master
Browse files Browse the repository at this point in the history
Add SSL support to mongo driver. Fixes vibe-d#575.
  • Loading branch information
s-ludwig committed Mar 19, 2014
2 parents 8202a05 + 5fb96a9 commit 0bb9902
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 7 deletions.
39 changes: 34 additions & 5 deletions source/vibe/db/mongo/connection.d
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -105,6 +106,7 @@ class MongoConnection {
private {
MongoClientSettings m_settings;
TCPConnection m_conn;
Stream m_stream;
ulong m_bytesRead;
int m_msgid = 1;
}
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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); }
Expand All @@ -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++; }

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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"));
Expand All @@ -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 == "");
Expand All @@ -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,
Expand Down Expand Up @@ -769,6 +796,8 @@ class MongoClientSettings
bool journal;
long connectTimeoutMS;
long socketTimeoutMS;
bool ssl;
bool sslverifycertificate = true;

static string makeDigest(string username, string password)
{
Expand Down
11 changes: 9 additions & 2 deletions source/vibe/db/mongo/mongo.d
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down

0 comments on commit 0bb9902

Please sign in to comment.