Permalink
Browse files

CSHARP-603: implemented Sasl authentication support as well as suppor…

…t for new delegated authentication support in server 2.4.
  • Loading branch information...
1 parent e0f958e commit 401a45f2d6cbb46171a2212945c4fab4bb60b0a7 @craiggwilson craiggwilson committed Jan 17, 2013
Showing with 5,206 additions and 1,888 deletions.
  1. +6 −213 MongoDB.Driver/Communication/MongoConnection.cs
  2. +10 −33 MongoDB.Driver/Communication/MongoConnectionPool.cs
  3. +6 −23 MongoDB.Driver/Communication/MongoServerInstance.cs
  4. +112 −0 MongoDB.Driver/Communication/Security/Authenticator.cs
  5. +50 −0 MongoDB.Driver/Communication/Security/IAuthenticationMethod.cs
  6. +51 −0 MongoDB.Driver/Communication/Security/ISaslMechanism.cs
  7. +36 −0 MongoDB.Driver/Communication/Security/ISaslStep.cs
  8. +66 −0 MongoDB.Driver/Communication/Security/Mechanisms/CramMD5Mechanism.cs
  9. +68 −0 MongoDB.Driver/Communication/Security/Mechanisms/DigestMD5Mechanism.cs
  10. +148 −0 MongoDB.Driver/Communication/Security/Mechanisms/Gsasl/Gsasl.cs
  11. +104 −0 MongoDB.Driver/Communication/Security/Mechanisms/Gsasl/GsaslContext.cs
  12. +57 −0 MongoDB.Driver/Communication/Security/Mechanisms/Gsasl/GsaslException.cs
  13. +57 −0 MongoDB.Driver/Communication/Security/Mechanisms/Gsasl/GsaslProperty.cs
  14. +144 −0 MongoDB.Driver/Communication/Security/Mechanisms/Gsasl/GsaslSession.cs
  15. +67 −0 MongoDB.Driver/Communication/Security/Mechanisms/GsaslCramMD5Implementation.cs
  16. +67 −0 MongoDB.Driver/Communication/Security/Mechanisms/GsaslGssapiImplementation.cs
  17. +144 −0 MongoDB.Driver/Communication/Security/Mechanisms/GsaslImplementationBase.cs
  18. +78 −0 MongoDB.Driver/Communication/Security/Mechanisms/GssapiMechanism.cs
  19. +79 −0 MongoDB.Driver/Communication/Security/Mechanisms/ManagedCramMD5Implementation.cs
  20. +334 −0 MongoDB.Driver/Communication/Security/Mechanisms/ManagedDigestMD5Implementation.cs
  21. +55 −0 MongoDB.Driver/Communication/Security/Mechanisms/SaslImplementationBase.cs
  22. +95 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/AuthIdentity.cs
  23. +32 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/AuthIdentityFlag.cs
  24. +36 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/DataRepresentation.cs
  25. +32 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/EncryptQualityOfProtection.cs
  26. +32 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/QueryContextAttribute.cs
  27. +94 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SecurityBuffer.cs
  28. +175 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SecurityBufferDescriptor.cs
  29. +48 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SecurityBufferType.cs
  30. +371 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SecurityContext.cs
  31. +31 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SecurityCredentialUse.cs
  32. +124 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SecurityCredentials.cs
  33. +34 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SecurityPackageContextSizes.cs
  34. +44 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SspiContextFlags.cs
  35. +68 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SspiHandle.cs
  36. +28 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/SspiPackage.cs
  37. +321 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/Win32.cs
  38. +57 −0 MongoDB.Driver/Communication/Security/Mechanisms/Sspi/Win32Exception.cs
  39. +210 −0 MongoDB.Driver/Communication/Security/Mechanisms/WindowsGssapiImplementation.cs
  40. +84 −0 MongoDB.Driver/Communication/Security/MongoCRAuthenticationMethod.cs
  41. +56 −0 MongoDB.Driver/Communication/Security/MongoSecurityException.cs
  42. +114 −0 MongoDB.Driver/Communication/Security/SaslAuthenticationMethod.cs
  43. +67 −0 MongoDB.Driver/Communication/Security/SaslCompletionStep.cs
  44. +87 −0 MongoDB.Driver/Communication/Security/SaslConversation.cs
  45. +32 −0 MongoDB.Driver/MongoAuthenticationProtocol.cs
  46. +21 −28 MongoDB.Driver/MongoClientSettings.cs
  47. +3 −3 MongoDB.Driver/MongoCollection.cs
  48. +44 −0 MongoDB.Driver/MongoConnectionStringBuilder.cs
  49. +156 −52 MongoDB.Driver/MongoCredentials.cs
  50. +43 −62 MongoDB.Driver/MongoCredentialsStore.cs
  51. +3 −3 MongoDB.Driver/MongoCursorEnumerator.cs
  52. +48 −0 MongoDB.Driver/MongoDB.Driver.csproj
  53. +2 −60 MongoDB.Driver/MongoDatabase.cs
  54. +2 −64 MongoDB.Driver/MongoDatabaseSettings.cs
  55. +45 −0 MongoDB.Driver/MongoExternalIdentity.cs
  56. +137 −0 MongoDB.Driver/MongoIdentity.cs
  57. +84 −0 MongoDB.Driver/MongoIdentityEvidence.cs
  58. +37 −0 MongoDB.Driver/MongoInternalIdentity.cs
  59. +13 −137 MongoDB.Driver/MongoServer.cs
  60. +25 −63 MongoDB.Driver/MongoServerSettings.cs
  61. +40 −10 MongoDB.Driver/MongoUrl.cs
  62. +99 −29 MongoDB.Driver/MongoUrlBuilder.cs
  63. +13 −6 MongoDB.Driver/MongoUser.cs
  64. +165 −0 MongoDB.Driver/PasswordEvidence.cs
  65. +57 −0 MongoDB.Driver/ProcessEvidence.cs
  66. +6 −6 MongoDB.DriverUnitTests/Jira/CSharp346Tests.cs
  67. +13 −24 MongoDB.DriverUnitTests/MongoClientSettingsTests.cs
  68. +35 −0 MongoDB.DriverUnitTests/MongoConnectionStringBuilderTests.cs
  69. +9 −30 MongoDB.DriverUnitTests/MongoCredentialTests.cs
  70. +0 −26 MongoDB.DriverUnitTests/MongoDatabaseSettingsTests.cs
  71. +1 −1 MongoDB.DriverUnitTests/MongoDatabaseTests.cs
  72. +19 −52 MongoDB.DriverUnitTests/MongoServerSettingsTests.cs
  73. +0 −1 MongoDB.DriverUnitTests/MongoServerTests.cs
  74. +59 −17 MongoDB.DriverUnitTests/MongoUrlBuilderTests.cs
  75. +10 −939 MongoDB.DriverUnitTests/MongoUrlTests.cs
  76. +6 −6 MongoDB.DriverUnitTests/MongoUserTests.cs
@@ -14,14 +14,15 @@
*/
using System;
-using System.Collections.Generic;
using System.IO;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using MongoDB.Bson;
using MongoDB.Bson.IO;
using MongoDB.Bson.Serialization;
+using MongoDB.Driver.Communication;
+using MongoDB.Driver.Communication.Security;
namespace MongoDB.Driver.Internal
{
@@ -61,16 +62,13 @@ public class MongoConnection
private DateTime _lastUsedAt; // set every time the connection is Released
private int _messageCounter;
private int _requestId;
- private Dictionary<string, Authentication> _authentications = new Dictionary<string, Authentication>();
// constructors
internal MongoConnection(MongoConnectionPool connectionPool)
+ : this(connectionPool.ServerInstance)
{
- _serverInstance = connectionPool.ServerInstance;
_connectionPool = connectionPool;
_generationId = connectionPool.GenerationId;
- _createdAt = DateTime.UtcNow;
- _state = MongoConnectionState.Initial;
}
internal MongoConnection(MongoServerInstance serverInstance)
@@ -147,138 +145,6 @@ public MongoConnectionState State
}
// internal methods
- internal void Authenticate(string databaseName, MongoCredentials credentials)
- {
- if (_state == MongoConnectionState.Closed) { throw new InvalidOperationException("Connection is closed."); }
- lock (_connectionLock)
- {
- var nonceCommand = new CommandDocument("getnonce", 1);
- var commandResult = RunCommand(databaseName, QueryFlags.None, nonceCommand, false);
- if (!commandResult.Ok)
- {
- throw new MongoAuthenticationException(
- "Error getting nonce for authentication.",
- new MongoCommandException(commandResult));
- }
-
- var nonce = commandResult.Response["nonce"].AsString;
- var passwordDigest = MongoUtils.Hash(credentials.Username + ":mongo:" + credentials.Password);
- var digest = MongoUtils.Hash(nonce + credentials.Username + passwordDigest);
- var authenticateCommand = new CommandDocument
- {
- { "authenticate", 1 },
- { "user", credentials.Username },
- { "nonce", nonce },
- { "key", digest }
- };
-
- commandResult = RunCommand(databaseName, QueryFlags.None, authenticateCommand, false);
- if (!commandResult.Ok)
- {
- var message = string.Format("Invalid credentials for database '{0}'.", databaseName);
- throw new MongoAuthenticationException(
- message,
- new MongoCommandException(commandResult));
- }
-
- var authentication = new Authentication(credentials);
- _authentications.Add(databaseName, authentication);
- }
- }
-
- // check whether the connection can be used with the given database (and credentials)
- // the following are the only valid authentication states for a connection:
- // 1. the connection is not authenticated against any database
- // 2. the connection has a single authentication against the admin database (with a particular set of credentials)
- // 3. the connection has one or more authentications against any databases other than admin
- // (with the restriction that a particular database can only be authenticated against once and therefore with only one set of credentials)
-
- // assume that IsAuthenticated was called first and returned false
- internal bool CanAuthenticate(string databaseName, MongoCredentials credentials)
- {
- if (_state == MongoConnectionState.Closed) { throw new InvalidOperationException("Connection is closed."); }
- if (databaseName == null)
- {
- return true;
- }
-
- if (_authentications.Count == 0)
- {
- // a connection with no existing authentications can authenticate anything
- return true;
- }
- else
- {
- // a connection with existing authentications can't be used without credentials
- if (credentials == null)
- {
- return false;
- }
-
- // a connection with existing authentications can't be used with new admin credentials
- if (credentials.Admin)
- {
- return false;
- }
-
- // a connection with an existing authentication to the admin database can't be used with any other credentials
- if (_authentications.ContainsKey("admin"))
- {
- return false;
- }
-
- // a connection with an existing authentication to a database can't authenticate for the same database again
- if (_authentications.ContainsKey(databaseName))
- {
- return false;
- }
-
- return true;
- }
- }
-
- internal void CheckAuthentication(string databaseName, MongoCredentials credentials)
- {
- if (_state == MongoConnectionState.Closed) { throw new InvalidOperationException("Connection is closed."); }
- if (credentials == null)
- {
- if (_authentications.Count != 0)
- {
- throw new InvalidOperationException("Connection requires credentials.");
- }
- }
- else
- {
- var authenticationDatabaseName = credentials.Admin ? "admin" : databaseName;
- Authentication authentication;
- if (_authentications.TryGetValue(authenticationDatabaseName, out authentication))
- {
- if (authentication.Credentials != credentials)
- {
- // this shouldn't happen because a connection would have been chosen from the connection pool only if it was viable
- if (authenticationDatabaseName == "admin")
- {
- throw new MongoInternalException("Connection already authenticated to the admin database with different credentials.");
- }
- else
- {
- throw new MongoInternalException("Connection already authenticated to the database with different credentials.");
- }
- }
- authentication.LastUsed = DateTime.UtcNow;
- }
- else
- {
- if (authenticationDatabaseName == "admin" && _authentications.Count != 0)
- {
- // this shouldn't happen because a connection would have been chosen from the connection pool only if it was viable
- throw new MongoInternalException("The connection cannot be authenticated against the admin database because it is already authenticated against other databases.");
- }
- Authenticate(authenticationDatabaseName, credentials);
- }
- }
- }
-
internal void Close()
{
lock (_connectionLock)
@@ -305,61 +171,13 @@ internal void Close()
}
}
- internal bool IsAuthenticated(string databaseName, MongoCredentials credentials)
- {
- if (_state == MongoConnectionState.Closed) { throw new InvalidOperationException("Connection is closed."); }
- if (databaseName == null)
- {
- return true;
- }
-
- lock (_connectionLock)
- {
- if (credentials == null)
- {
- return _authentications.Count == 0;
- }
- else
- {
- var authenticationDatabaseName = credentials.Admin ? "admin" : databaseName;
- Authentication authentication;
- if (_authentications.TryGetValue(authenticationDatabaseName, out authentication))
- {
- return credentials == authentication.Credentials;
- }
- else
- {
- return false;
- }
- }
- }
- }
-
internal bool IsExpired()
{
var now = DateTime.UtcNow;
return now > _createdAt + _serverInstance.Settings.MaxConnectionLifeTime
|| now > _lastUsedAt + _serverInstance.Settings.MaxConnectionIdleTime;
}
- internal void Logout(string databaseName)
- {
- if (_state == MongoConnectionState.Closed) { throw new InvalidOperationException("Connection is closed."); }
- lock (_connectionLock)
- {
- var logoutCommand = new CommandDocument("logout", 1);
- var commandResult = RunCommand(databaseName, QueryFlags.None, logoutCommand, false);
- if (!commandResult.Ok)
- {
- throw new MongoAuthenticationException(
- "Error logging off.",
- new MongoCommandException(commandResult));
- }
-
- _authentications.Remove(databaseName);
- }
- }
-
internal void Open()
{
if (_state != MongoConnectionState.Initial)
@@ -405,6 +223,9 @@ internal void Open()
_tcpClient = tcpClient;
_stream = stream;
_state = MongoConnectionState.Open;
+
+ new Authenticator(this, _serverInstance.Settings.CredentialsStore)
+ .Authenticate();
}
// this is a low level method that doesn't require a MongoServer
@@ -629,33 +450,5 @@ private HandleExceptionAction DetermineAction(Exception ex)
return HandleExceptionAction.CloseConnection; // this should always be the default action
}
-
- // private nested classes
- // keeps track of what credentials were used with a given database
- // and when that database was last used on this connection
- private class Authentication
- {
- // private fields
- private MongoCredentials _credentials;
- private DateTime _lastUsed;
-
- // constructors
- public Authentication(MongoCredentials credentials)
- {
- _credentials = credentials;
- _lastUsed = DateTime.UtcNow;
- }
-
- public MongoCredentials Credentials
- {
- get { return _credentials; }
- }
-
- public DateTime LastUsed
- {
- get { return _lastUsed; }
- set { _lastUsed = value; }
- }
- }
}
}
@@ -16,6 +16,7 @@
using System;
using System.Collections.Generic;
using System.Threading;
+using MongoDB.Driver.Communication;
namespace MongoDB.Driver.Internal
{
@@ -86,12 +87,12 @@ public MongoServerInstance ServerInstance
}
// internal methods
- internal MongoConnection AcquireConnection(string databaseName, MongoCredentials credentials)
+ internal MongoConnection AcquireConnection()
{
- return AcquireConnection(databaseName, credentials, _defaultAcquireConnectionOptions);
+ return AcquireConnection(_defaultAcquireConnectionOptions);
}
- internal MongoConnection AcquireConnection(string databaseName, MongoCredentials credentials, AcquireConnectionOptions options)
+ internal MongoConnection AcquireConnection(AcquireConnectionOptions options)
{
MongoConnection connectionToClose = null;
try
@@ -112,39 +113,15 @@ internal MongoConnection AcquireConnection(string databaseName, MongoCredentials
{
if (_availableConnections.Count > 0)
{
- // first try to find the most recently used connection that is already authenticated for this database
- for (int i = _availableConnections.Count - 1; i >= 0; i--)
+ var connection = _availableConnections[_availableConnections.Count - 1];
+ if (connection.IsExpired())
{
- var connection = _availableConnections[i];
- if (connection.IsExpired())
- {
- _availableConnections.RemoveAt(i);
- connectionToClose = connection;
- return new MongoConnection(this);
- }
- else if (connection.IsAuthenticated(databaseName, credentials))
- {
- _availableConnections.RemoveAt(i);
- return connection;
- }
+ connectionToClose = connection;
+ connection = new MongoConnection(this);
}
- // otherwise find the most recently used connection that can be authenticated for this database
- for (int i = _availableConnections.Count - 1; i >= 0; i--)
- {
- var connection = _availableConnections[i];
- if (connection.CanAuthenticate(databaseName, credentials))
- {
- _availableConnections.RemoveAt(i);
- return connection;
- }
- }
-
- // otherwise replace the least recently used connection with a brand new one
- // if this happens a lot the connection pool size should be increased
- connectionToClose = _availableConnections[0];
- _availableConnections.RemoveAt(0);
- return new MongoConnection(this);
+ _availableConnections.RemoveAt(_availableConnections.Count - 1);
+ return connection;
}
// avoid waiting by creating a new connection if options allow it
Oops, something went wrong.

0 comments on commit 401a45f

Please sign in to comment.