Skip to content

Commit

Permalink
CSHARP-314: Added support for SSL connections.
Browse files Browse the repository at this point in the history
  • Loading branch information
rstam committed Jul 28, 2012
1 parent 30cb887 commit 8ac8475
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 5 deletions.
41 changes: 40 additions & 1 deletion Driver/Core/MongoConnectionStringBuilder.cs
Expand Up @@ -41,6 +41,7 @@ public class MongoConnectionStringBuilder : DbConnectionStringBuilder
{ "database", "database" },
{ "fsync", "fsync" },
{ "guids", "uuidRepresentation" },
{ "ipv6", "ipv6" },
{ "j", "journal" },
{ "journal", "journal" },
{ "maxidletime", "maxIdleTime" },
Expand All @@ -59,6 +60,8 @@ public class MongoConnectionStringBuilder : DbConnectionStringBuilder
{ "slaveok", "slaveOk" },
{ "sockettimeout", "socketTimeout" },
{ "sockettimeoutms", "socketTimeout" },
{ "ssl", "ssl" },
{ "sslverifycertificate", "sslVerifyCertificate" },
{ "username", "username" },
{ "uuidrepresentation", "uuidRepresentation" },
{ "w", "w" },
Expand Down Expand Up @@ -89,6 +92,8 @@ public class MongoConnectionStringBuilder : DbConnectionStringBuilder
private bool? _slaveOk;
private TimeSpan _socketTimeout;
private string _username;
private bool _useSsl;
private bool _verifySslCertificate;
private double _waitQueueMultiple;
private int _waitQueueSize;
private TimeSpan _waitQueueTimeout;
Expand Down Expand Up @@ -439,6 +444,32 @@ public string Username
}
}

/// <summary>
/// Gets or sets whether to use SSL.
/// </summary>
public bool UseSsl
{
get { return _useSsl; }
set
{
_useSsl = value;
base["ssl"] = XmlConvert.ToString(value);
}
}

/// <summary>
/// Gets or sets whether to verify an SSL certificate.
/// </summary>
public bool VerifySslCertificate
{
get { return _verifySslCertificate; }
set
{
_verifySslCertificate = value;
base["sslVerifyCertificate"] = XmlConvert.ToString(value);
}
}

/// <summary>
/// Gets or sets the wait queue multiple (the actual wait queue size will be WaitQueueMultiple x MaxConnectionPoolSize).
/// </summary>
Expand Down Expand Up @@ -599,6 +630,12 @@ public TimeSpan WaitQueueTimeout
case "sockettimeoutms":
SocketTimeout = ToTimeSpan(keyword, value);
break;
case "ssl":
UseSsl = Convert.ToBoolean(value);
break;
case "sslverifycertificate":
VerifySslCertificate = Convert.ToBoolean(value);
break;
case "username":
Username = (string)value;
break;
Expand Down Expand Up @@ -667,7 +704,7 @@ public MongoServerSettings ToServerSettings()
var readPreference = ReadPreference ?? ReadPreference.Primary;
return new MongoServerSettings(_connectionMode, _connectTimeout, null, defaultCredentials, _guidRepresentation, _ipv6,
_maxConnectionIdleTime, _maxConnectionLifeTime, _maxConnectionPoolSize, _minConnectionPoolSize, readPreference, _replicaSetName,
_safeMode ?? MongoDefaults.SafeMode, _servers, _socketTimeout, ComputedWaitQueueSize,_waitQueueTimeout);
_safeMode ?? MongoDefaults.SafeMode, _servers, _socketTimeout, _useSsl, _verifySslCertificate, ComputedWaitQueueSize, _waitQueueTimeout);
}

// private methods
Expand Down Expand Up @@ -740,6 +777,8 @@ private void ResetValues()
_slaveOk = null;
_socketTimeout = MongoDefaults.SocketTimeout;
_username = null;
_useSsl = false;
_verifySslCertificate = true;
_waitQueueMultiple = MongoDefaults.WaitQueueMultiple;
_waitQueueSize = MongoDefaults.WaitQueueSize;
_waitQueueTimeout = MongoDefaults.WaitQueueTimeout;
Expand Down
44 changes: 43 additions & 1 deletion Driver/Core/MongoServerSettings.cs
Expand Up @@ -47,6 +47,8 @@ public class MongoServerSettings
private List<MongoServerAddress> _servers;
private ReadOnlyCollection<MongoServerAddress> _serversReadOnly;
private TimeSpan _socketTimeout;
private bool _useSsl;
private bool _verifySslCertificate;
private int _waitQueueSize;
private TimeSpan _waitQueueTimeout;

Expand Down Expand Up @@ -77,6 +79,8 @@ public MongoServerSettings()
_servers = new List<MongoServerAddress> { new MongoServerAddress("localhost") };
_serversReadOnly = new ReadOnlyCollection<MongoServerAddress>(_servers);
_socketTimeout = MongoDefaults.SocketTimeout;
_useSsl = false;
_verifySslCertificate = true;
_waitQueueSize = MongoDefaults.ComputedWaitQueueSize;
_waitQueueTimeout = MongoDefaults.WaitQueueTimeout;
}
Expand All @@ -99,6 +103,8 @@ public MongoServerSettings()
/// <param name="safeMode">The safe mode.</param>
/// <param name="servers">The server addresses (normally one unless it is the seed list for connecting to a replica set).</param>
/// <param name="socketTimeout">The socket timeout.</param>
/// <param name="useSsl">Whether to use SSL.</param>
/// <param name="verifySslCertificate">Whether to verify an SSL certificate.</param>
/// <param name="waitQueueSize">The wait queue size.</param>
/// <param name="waitQueueTimeout">The wait queue timeout.</param>
public MongoServerSettings(
Expand All @@ -117,6 +123,8 @@ public MongoServerSettings()
SafeMode safeMode,
IEnumerable<MongoServerAddress> servers,
TimeSpan socketTimeout,
bool useSsl,
bool verifySslCertificate,
int waitQueueSize,
TimeSpan waitQueueTimeout)
{
Expand Down Expand Up @@ -149,6 +157,8 @@ public MongoServerSettings()
_servers = new List<MongoServerAddress>(servers);
_serversReadOnly = new ReadOnlyCollection<MongoServerAddress>(_servers);
_socketTimeout = socketTimeout;
_useSsl = useSsl;
_verifySslCertificate = verifySslCertificate;
_waitQueueSize = waitQueueSize;
_waitQueueTimeout = waitQueueTimeout;
}
Expand Down Expand Up @@ -417,6 +427,32 @@ public TimeSpan SocketTimeout
}
}

/// <summary>
/// Gets or sets whether to use SSL.
/// </summary>
public bool UseSsl
{
get { return _useSsl; }
set
{
if (_isFrozen) { throw new InvalidOperationException("MongoServerSettings is frozen."); }
_useSsl = value;
}
}

/// <summary>
/// Gets or sets whether to verify an SSL certificate.
/// </summary>
public bool VerifySslCertificate
{
get { return _verifySslCertificate; }
set
{
if (_isFrozen) { throw new InvalidOperationException("MongoServerSettings is frozen."); }
_verifySslCertificate = value;
}
}

/// <summary>
/// Gets or sets the wait queue size.
/// </summary>
Expand Down Expand Up @@ -452,7 +488,7 @@ public MongoServerSettings Clone()
{
return new MongoServerSettings(_connectionMode, _connectTimeout, _credentialsStore.Clone(), _defaultCredentials,
_guidRepresentation, _ipv6, _maxConnectionIdleTime, _maxConnectionLifeTime, _maxConnectionPoolSize,
_minConnectionPoolSize, _readPreference, _replicaSetName, _safeMode, _servers, _socketTimeout,
_minConnectionPoolSize, _readPreference, _replicaSetName, _safeMode, _servers, _socketTimeout, _useSsl, _verifySslCertificate,
_waitQueueSize, _waitQueueTimeout);
}

Expand Down Expand Up @@ -492,6 +528,8 @@ public override bool Equals(object obj)
_safeMode == rhs._safeMode &&
_servers.SequenceEqual(rhs._servers) &&
_socketTimeout == rhs._socketTimeout &&
_useSsl == rhs._useSsl &&
_verifySslCertificate == rhs._verifySslCertificate &&
_waitQueueSize == rhs._waitQueueSize &&
_waitQueueTimeout == rhs._waitQueueTimeout;
}
Expand Down Expand Up @@ -593,6 +631,8 @@ public override int GetHashCode()
hash = 37 * hash + server.GetHashCode();
}
hash = 37 * hash + _socketTimeout.GetHashCode();
hash = 37 * hash + _useSsl.GetHashCode();
hash = 37 * hash + _verifySslCertificate.GetHashCode();
hash = 37 * hash + _waitQueueSize.GetHashCode();
hash = 37 * hash + _waitQueueTimeout.GetHashCode();
return hash;
Expand Down Expand Up @@ -625,6 +665,8 @@ public override string ToString()
sb.AppendFormat("SafeMode={0};", _safeMode);
sb.AppendFormat("Servers={0};", string.Join(",", _servers.Select(s => s.ToString()).ToArray()));
sb.AppendFormat("SocketTimeout={0};", _socketTimeout);
sb.AppendFormat("Ssl={0};", _useSsl);
sb.AppendFormat("SslVerifyCertificate={0};", _verifySslCertificate);
sb.AppendFormat("WaitQueueSize={0};", _waitQueueSize);
sb.AppendFormat("WaitQueueTimeout={0}", _waitQueueTimeout);
return sb.ToString();
Expand Down
16 changes: 16 additions & 0 deletions Driver/Core/MongoUrl.cs
Expand Up @@ -246,6 +246,22 @@ public string Url
get { return _url; }
}

/// <summary>
/// Gets whether to use SSL.
/// </summary>
public bool UseSsl
{
get { return _serverSettings.UseSsl; }
}

/// <summary>
/// Gets whether to verify an SSL certificate.
/// </summary>
public bool VerifySslCertificate
{
get { return _serverSettings.VerifySslCertificate; }
}

/// <summary>
/// Gets the wait queue multiple (the actual wait queue size will be WaitQueueMultiple x MaxConnectionPoolSize).
/// </summary>
Expand Down
38 changes: 37 additions & 1 deletion Driver/Core/MongoUrlBuilder.cs
Expand Up @@ -50,6 +50,8 @@ public class MongoUrlBuilder
private IEnumerable<MongoServerAddress> _servers;
private bool? _slaveOk;
private TimeSpan _socketTimeout;
private bool _useSsl;
private bool _verifySslCertificate;
private double _waitQueueMultiple;
private int _waitQueueSize;
private TimeSpan _waitQueueTimeout;
Expand Down Expand Up @@ -287,6 +289,24 @@ public TimeSpan SocketTimeout
set { _socketTimeout = value; }
}

/// <summary>
/// Gets or sets whether to use SSL.
/// </summary>
public bool UseSsl
{
get { return _useSsl; }
set { _useSsl = value; }
}

/// <summary>
/// Gets or sets whether to verify an SSL certificate.
/// </summary>
public bool VerifySslCertificate
{
get { return _verifySslCertificate; }
set { _verifySslCertificate = value; }
}

/// <summary>
/// Gets or sets the wait queue multiple (the actual wait queue size will be WaitQueueMultiple x MaxConnectionPoolSize).
/// </summary>
Expand Down Expand Up @@ -624,6 +644,12 @@ public void Parse(string url)
case "sockettimeoutms":
_socketTimeout = ParseTimeSpan(name, value);
break;
case "ssl":
_useSsl = ParseBoolean(name, value);
break;
case "sslverifycertificate":
_verifySslCertificate = ParseBoolean(name, value);
break;
case "w":
if (_safeMode == null) { _safeMode = new SafeMode(false); }
try
Expand Down Expand Up @@ -680,7 +706,7 @@ public MongoServerSettings ToServerSettings()
var readPreference = ReadPreference ?? ReadPreference.Primary;
return new MongoServerSettings(_connectionMode, _connectTimeout, null, _defaultCredentials, _guidRepresentation, _ipv6,
_maxConnectionIdleTime, _maxConnectionLifeTime, _maxConnectionPoolSize, _minConnectionPoolSize, readPreference, _replicaSetName,
_safeMode ?? MongoDefaults.SafeMode, _servers, _socketTimeout, ComputedWaitQueueSize, _waitQueueTimeout);
_safeMode ?? MongoDefaults.SafeMode, _servers, _socketTimeout, _useSsl, _verifySslCertificate, ComputedWaitQueueSize, _waitQueueTimeout);
}

/// <summary>
Expand Down Expand Up @@ -722,6 +748,14 @@ public override string ToString()
{
query.AppendFormat("ipv6=true;");
}
if (_useSsl)
{
query.AppendFormat("ssl=true;");
if (!_verifySslCertificate)
{
query.AppendFormat("sslVerifyCertificate=false;");
}
}
if (_connectionMode == ConnectionMode.Direct && _servers != null && _servers.Count() != 1 ||
_connectionMode == ConnectionMode.ReplicaSet && (_servers == null || _servers.Count() == 1))
{
Expand Down Expand Up @@ -845,6 +879,8 @@ private void ResetValues()
_servers = null;
_slaveOk = null;
_socketTimeout = MongoDefaults.SocketTimeout;
_useSsl = false;
_verifySslCertificate = true;
_waitQueueMultiple = MongoDefaults.WaitQueueMultiple;
_waitQueueSize = MongoDefaults.WaitQueueSize;
_waitQueueTimeout = MongoDefaults.WaitQueueTimeout;
Expand Down
51 changes: 49 additions & 2 deletions Driver/Internal/MongoConnection.cs
Expand Up @@ -18,7 +18,9 @@
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;

using MongoDB.Bson;
Expand Down Expand Up @@ -58,6 +60,7 @@ public class MongoConnection
private int _generationId; // the generationId of the connection pool at the time this connection was created
private MongoConnectionState _state;
private TcpClient _tcpClient;
private Stream _stream; // either a NetworkStream or an SslStream wrapping a NetworkStream
private DateTime _createdAt;
private DateTime _lastUsedAt; // set every time the connection is Released
private int _messageCounter;
Expand Down Expand Up @@ -287,6 +290,11 @@ internal void Close()
{
if (_state != MongoConnectionState.Closed)
{
if (_stream != null)
{
try { _stream.Close(); } catch { } // ignore exceptions
_stream = null;
}
if (_tcpClient != null)
{
if (_tcpClient.Connected)
Expand Down Expand Up @@ -364,7 +372,36 @@ internal void Open()
tcpClient.SendBufferSize = MongoDefaults.TcpSendBufferSize;
tcpClient.Connect(ipEndPoint);

var stream = (Stream)tcpClient.GetStream();
if (_serverInstance.Server.Settings.UseSsl)
{
SslStream sslStream;
if (_serverInstance.Server.Settings.VerifySslCertificate)
{
sslStream = new SslStream(stream, false); // don't leave inner stream open
}
else
{
sslStream = new SslStream(stream, false, AcceptAnyCertificate, null); // don't leave inner stream open
}

try
{
sslStream.AuthenticateAsClient(_serverInstance.Address.Host);
}
catch
{
try { stream.Close(); }
catch { } // ignore exceptions
try { tcpClient.Close(); }
catch { } // ignore exceptions
throw;
}
stream = sslStream;
}

_tcpClient = tcpClient;
_stream = stream;
_state = MongoConnectionState.Open;
}

Expand Down Expand Up @@ -518,13 +555,23 @@ internal SafeModeResult SendMessage(MongoRequestMessage message, SafeMode safeMo
}

// private methods
private NetworkStream GetNetworkStream()
private bool AcceptAnyCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
)
{
return true;
}

private Stream GetNetworkStream()
{
if (_state == MongoConnectionState.Initial)
{
Open();
}
return _tcpClient.GetStream();
return _stream;
}

private void HandleException(Exception ex)
Expand Down

0 comments on commit 8ac8475

Please sign in to comment.