Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Move Hash function to its own class.

Move Authentication to Connection and ensure it authenticates per Database.
Fix some more tests.
  • Loading branch information...
commit 9ce6e5935f16808a529ee6727368f7bd660f75d2 1 parent ffcefd6
@lanwin lanwin authored
View
263 MongoDB.Net-Tests/TestMongoSymbol.cs
@@ -1,143 +1,120 @@
-
-using System;
-using System.Text;
-
-using NUnit.Framework;
-
-namespace MongoDB.Driver
-{
-
-
- [TestFixture()]
- public class TestMongoSymbol{
-
- [Test]
- public void TestValue(){
- Assert.IsTrue(string.IsInterned("s") != null);
-
- MongoSymbol s = new MongoSymbol("s");
- Assert.IsNotNull(s.Value);
- Assert.IsTrue(string.IsInterned(s.Value) != null, "First value was not interned");
-
- string val = new StringBuilder().Append('s').ToString();
- Assert.IsFalse(string.IsInterned(val) == null);
- MongoSymbol s2 = new MongoSymbol(val);
- Assert.IsTrue(string.IsInterned(s2.Value) != null, "Second value was not interned");
-
- Assert.IsTrue(System.Object.ReferenceEquals(s.Value, s2.Value));
-
- }
-
- [Test]
- public void TestNullSymbolValue(){
- bool thrown = false;
- try{
- MongoSymbol s = new MongoSymbol(null);
- }catch(ArgumentNullException){
- thrown = true;
- }
- Assert.IsTrue(thrown);
- }
-
- [Test]
- public void TestComparing(){
- MongoSymbol a = new MongoSymbol("a");
- MongoSymbol a2 = new MongoSymbol("a");
- MongoSymbol b = new MongoSymbol("b");
-
- Assert.AreEqual(0, a.CompareTo(a2));
- Assert.AreEqual(0, a2.CompareTo(a2));
-
- Assert.AreEqual(-1, a.CompareTo(b));
- Assert.AreEqual(1, b.CompareTo(a));
-
- }
-
- [Test]
- public void TestEquals(){
- MongoSymbol a = new MongoSymbol("a");
- MongoSymbol a2 = new MongoSymbol("a");
- string astr = "a";
-
- MongoSymbol b = new MongoSymbol("b");
- string bstr = "b";
-
- Assert.IsTrue(a.Equals(a2));
- Assert.IsTrue(a2.Equals(a));
- Assert.IsTrue(a.Equals(astr));
-
- Assert.IsFalse(a.Equals(b));
- Assert.IsFalse(b.Equals(a));
- Assert.IsFalse(a.Equals(bstr));
-
-
-
- }
-
- [Test]
- public void TestEqOperator(){
- MongoSymbol a = new MongoSymbol("a");
- MongoSymbol a2 = new MongoSymbol("a");
- string astr = "a";
-
- MongoSymbol b = new MongoSymbol("b");
- string bstr = "b";
-
- Assert.IsTrue(a == a);
- Assert.IsTrue(a == a2);
- Assert.IsTrue(a2 == a);
- Assert.IsTrue(a == astr);
- Assert.IsTrue(astr == a);
-
- Assert.IsTrue(a == new StringBuilder().Append('a').ToString()); //Not interned like the hard coded ones above.
-
- Assert.IsFalse(a == b);
- Assert.IsFalse(a == bstr);
- Assert.IsFalse(bstr == a);
-
- Assert.IsFalse(a == null);
- }
-
- [Test]
- public void TestNotEqOperator(){
- MongoSymbol a = new MongoSymbol("a");
- MongoSymbol a2 = new MongoSymbol("a");
- string astr = "a";
-
- MongoSymbol b = new MongoSymbol("b");
- string bstr = "b";
-
- Assert.IsFalse(a != a);
- Assert.IsFalse(a != a2);
- Assert.IsFalse(a2 != a);
- Assert.IsFalse(a != astr);
- Assert.IsFalse(astr != a);
-
- Assert.IsTrue(a != b);
- Assert.IsTrue(a != bstr);
- Assert.IsTrue(bstr != a);
-
- Assert.IsTrue(a != null);
- }
-
- [Test]
- public void TestEmpty(){
- MongoSymbol empty = MongoSymbol.Empty;
- Assert.IsTrue(MongoSymbol.IsEmpty(empty));
- Assert.IsFalse(MongoSymbol.IsEmpty(new MongoSymbol("a")));
- }
-
- [Test]
- public void TestToString(){
- string val = "symbol";
- MongoSymbol sym = new MongoSymbol(val);
-
- string str = sym;
- Assert.AreEqual(val, str);
- Assert.IsTrue(str == sym);
- Assert.AreEqual(str, sym.ToString());
-
- }
-
- }
-}
+using System.Text;
+using NUnit.Framework;
+
+namespace MongoDB.Driver
+{
+ [TestFixture]
+ public class TestMongoSymbol
+ {
+ [Test]
+ public void TestComparing(){
+ var a = new MongoSymbol("a");
+ var a2 = new MongoSymbol("a");
+ var b = new MongoSymbol("b");
+
+ Assert.AreEqual(0, a.CompareTo(a2));
+ Assert.AreEqual(0, a2.CompareTo(a2));
+
+ Assert.AreEqual(-1, a.CompareTo(b));
+ Assert.AreEqual(1, b.CompareTo(a));
+ }
+
+ [Test]
+ public void TestEmpty(){
+ var empty = MongoSymbol.Empty;
+ Assert.IsTrue(MongoSymbol.IsEmpty(empty));
+ Assert.IsFalse(MongoSymbol.IsEmpty(new MongoSymbol("a")));
+ }
+
+ [Test]
+ public void TestEqOperator(){
+ var a = new MongoSymbol("a");
+ var a2 = new MongoSymbol("a");
+ var astr = "a";
+
+ var b = new MongoSymbol("b");
+ var bstr = "b";
+
+ Assert.IsTrue(a == a);
+ Assert.IsTrue(a == a2);
+ Assert.IsTrue(a2 == a);
+ Assert.IsTrue(a == astr);
+ Assert.IsTrue(astr == a);
+
+ Assert.IsTrue(a == new StringBuilder().Append('a').ToString()); //Not interned like the hard coded ones above.
+
+ Assert.IsFalse(a == b);
+ Assert.IsFalse(a == bstr);
+ Assert.IsFalse(bstr == a);
+
+ Assert.IsFalse(a == null);
+ }
+
+ [Test]
+ public void TestEquals(){
+ var a = new MongoSymbol("a");
+ var a2 = new MongoSymbol("a");
+ var astr = "a";
+
+ var b = new MongoSymbol("b");
+ var bstr = "b";
+
+ Assert.IsTrue(a.Equals(a2));
+ Assert.IsTrue(a2.Equals(a));
+ Assert.IsTrue(a.Equals(astr));
+
+ Assert.IsFalse(a.Equals(b));
+ Assert.IsFalse(b.Equals(a));
+ Assert.IsFalse(a.Equals(bstr));
+ }
+
+ [Test]
+ public void TestNotEqOperator(){
+ var a = new MongoSymbol("a");
+ var a2 = new MongoSymbol("a");
+ var astr = "a";
+
+ var b = new MongoSymbol("b");
+ var bstr = "b";
+
+ Assert.IsFalse(a != a);
+ Assert.IsFalse(a != a2);
+ Assert.IsFalse(a2 != a);
+ Assert.IsFalse(a != astr);
+ Assert.IsFalse(astr != a);
+
+ Assert.IsTrue(a != b);
+ Assert.IsTrue(a != bstr);
+ Assert.IsTrue(bstr != a);
+
+ Assert.IsTrue(a != null);
+ }
+
+ [Test]
+ public void TestToString(){
+ var val = "symbol";
+ var sym = new MongoSymbol(val);
+
+ string str = sym;
+ Assert.AreEqual(val, str);
+ Assert.IsTrue(str == sym);
+ Assert.AreEqual(str, sym.ToString());
+ }
+
+ [Test]
+ public void TestValue(){
+ Assert.IsTrue(string.IsInterned("s") != null);
+
+ var s = new MongoSymbol("s");
+ Assert.IsNotNull(s.Value);
+ Assert.IsTrue(string.IsInterned(s.Value) != null, "First value was not interned");
+
+ var val = new StringBuilder().Append('s').ToString();
+ Assert.IsFalse(string.IsInterned(val) == null);
+ var s2 = new MongoSymbol(val);
+ Assert.IsTrue(string.IsInterned(s2.Value) != null, "Second value was not interned");
+
+ Assert.IsTrue(ReferenceEquals(s.Value, s2.Value));
+ }
+ }
+}
View
72 MongoDBDriver/Connections/Connection.cs
@@ -4,6 +4,7 @@
using MongoDB.Driver.Protocol;
using MongoDB.Driver.Results;
using MongoDB.Driver.Serialization;
+using MongoDB.Driver.Util;
namespace MongoDB.Driver.Connections
{
@@ -19,7 +20,7 @@ public class Connection : IDisposable
{
private readonly IConnectionFactory _factory;
private RawConnection _connection;
- private bool disposed = false;
+ private bool _disposed;
/// <summary>
/// Initializes a new instance of the <see cref="Connection"/> class.
@@ -43,23 +44,6 @@ public Connection(IConnectionFactory factory)
}
/// <summary>
- /// Gets or sets a value indicating whether this instance is authenticated.
- /// </summary>
- /// <value>
- /// <c>true</c> if this instance is authenticated; otherwise, <c>false</c>.
- /// </value>
- public bool IsAuthenticated {
- get { return _connection.IsAuthenticated; }
- }
-
- /// <summary>
- /// Masks as authenticated.
- /// </summary>
- public void MaskAuthenticated (){
- _connection.MarkAuthenticated ();
- }
-
- /// <summary>
/// Gets the connection string.
/// </summary>
/// <value>The connection string.</value>
@@ -196,6 +180,8 @@ public Connection(IConnectionFactory factory)
/// <returns></returns>
public Document SendCommand(ISerializationFactory factory, string database, Type rootType, Document command)
{
+ AuthenticateIfRequired(database);
+
var result = SendCommandCore<Document>(factory, database, rootType, command);
if((double)result["ok"] != 1.0)
@@ -223,6 +209,8 @@ public Document SendCommand(ISerializationFactory factory, string database, Type
public T SendCommand<T>(ISerializationFactory factory, string database, Type rootType, object command)
where T : CommandResultBase
{
+ AuthenticateIfRequired(database);
+
var result = SendCommandCore<T>(factory, database, rootType, command);
if(!result.Success)
@@ -274,6 +262,50 @@ private T SendCommandCore<T>(ISerializationFactory factory, string database, Typ
}
/// <summary>
+ /// Authenticates the on first request.
+ /// </summary>
+ /// <param name="databaseName">Name of the database.</param>
+ private void AuthenticateIfRequired(string databaseName)
+ {
+ if(databaseName == null)
+ throw new ArgumentNullException("databaseName");
+
+ if(_connection.IsAuthenticated(databaseName))
+ return;
+
+ var builder = new MongoConnectionStringBuilder(ConnectionString);
+
+ if(string.IsNullOrEmpty(builder.Username))
+ return;
+
+ var document = new Document().Add("getnonce", 1.0);
+ var nonceResult = SendCommandCore<Document>(SerializationFactory.Default, databaseName, typeof(Document), document);
+ var nonce = (string)nonceResult["nonce"];
+
+ if(nonce == null)
+ throw new MongoException("Error retrieving nonce", null);
+
+ var pwd = MongoHash.Generate(builder.Username + ":mongo:" + builder.Password);
+ var auth = new Document{
+ {"authenticate", 1.0},
+ {"user", builder.Username},
+ {"nonce", nonce},
+ {"key", MongoHash.Generate(nonce + builder.Username + pwd)}
+ };
+ try
+ {
+ SendCommandCore<Document>(SerializationFactory.Default, databaseName, typeof(Document), auth);
+ }
+ catch(MongoCommandException exception)
+ {
+ //Todo: use custom exception?
+ throw new MongoException("Authentication faild for " + builder.Username, exception);
+ }
+
+ _connection.MarkAuthenticated(databaseName);
+ }
+
+ /// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose (){
@@ -287,7 +319,7 @@ private T SendCommandCore<T>(ISerializationFactory factory, string database, Typ
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
- if(disposed)
+ if(_disposed)
return;
if (disposing)
@@ -299,7 +331,7 @@ protected virtual void Dispose(bool disposing)
// Cleanup Unmanaged Resources Here
// Then mark object as disposed
- disposed = true;
+ _disposed = true;
}
}
}
View
26 MongoDBDriver/Connections/RawConnection.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Net.Sockets;
namespace MongoDB.Driver.Connections
@@ -10,6 +11,7 @@ namespace MongoDB.Driver.Connections
public class RawConnection : IDisposable
{
private readonly TcpClient _client = new TcpClient();
+ private readonly List<string> _authenticatedDatabases = new List<string>();
private bool _isDisposed;
/// <summary>
@@ -84,19 +86,27 @@ public bool IsConnected
public MongoServerEndPoint EndPoint { get; private set; }
/// <summary>
- /// Gets or sets a value indicating whether this instance is authenticated.
+ /// Determines whether the specified database name is authenticated.
/// </summary>
- /// <value>
- /// <c>true</c> if this instance is authenticated; otherwise, <c>false</c>.
- /// </value>
- public bool IsAuthenticated { get; private set; }
+ /// <param name="databaseName">Name of the database.</param>
+ /// <returns>
+ /// <c>true</c> if the specified database name is authenticated; otherwise, <c>false</c>.
+ /// </returns>
+ public bool IsAuthenticated(string databaseName){
+ if(databaseName == null)
+ throw new ArgumentNullException("databaseName");
+
+ return _authenticatedDatabases.Contains(databaseName);
+ }
/// <summary>
/// Marks as authenticated.
/// </summary>
- public void MarkAuthenticated()
- {
- IsAuthenticated = true;
+ public void MarkAuthenticated(string databaseName){
+ if(databaseName == null)
+ throw new ArgumentNullException("databaseName");
+
+ _authenticatedDatabases.Add(databaseName);
}
/// <summary>
View
3  MongoDBDriver/DatabaseMetaData.cs
@@ -1,5 +1,6 @@
using MongoDB.Driver.Connections;
using MongoDB.Driver.Serialization;
+using MongoDB.Driver.Util;
namespace MongoDB.Driver
{
@@ -90,7 +91,7 @@ public bool DropDatabase()
public void AddUser(string username, string password)
{
var users = _database["system.users"];
- var pwd = MongoDatabase.Hash(username + ":mongo:" + password);
+ var pwd = MongoHash.Generate(username + ":mongo:" + password);
var user = new Document().Add("user", username).Add("pwd", pwd);
if(FindUser(username) != null)
View
14 MongoDBDriver/MongoCollection_1.cs
@@ -200,12 +200,14 @@ public MongoCollection(ISerializationFactory serializationFactory, Connection co
public T FindAndModify(object document, object spec, object sort, bool returnNew){
try
{
- var response = _database.SendCommand<FindAndModifyResult<T>>(new Document{
- {"findandmodify", Name},
- {"query", spec},
- {"update", EnsureUpdateDocument(document)},
- {"sort", sort},
- {"new", returnNew}});
+ var command = new Document
+ {
+ {"findandmodify", Name},
+ {"query", spec},
+ {"update", EnsureUpdateDocument(document)},
+ {"sort", sort},
+ {"new", returnNew}
+ };
var response = _connection.SendCommand<FindAndModifyResult<T>>(_serializationFactory,
DatabaseName,
View
1  MongoDBDriver/MongoDB.Driver.csproj
@@ -248,6 +248,7 @@
<Compile Include="Cursor_1.cs" />
<Compile Include="ICursor_1.cs" />
<Compile Include="IMongoCollection_1.cs" />
+ <Compile Include="Util\MongoHash.cs" />
<Compile Include="Util\ReflectionExtensions.cs" />
<Compile Include="MongoSymbol.cs" />
</ItemGroup>
View
53 MongoDBDriver/MongoDatabase.cs
@@ -248,7 +248,6 @@ public MongoDatabase(ISerializationFactory serializationFactory, Connection conn
/// <returns></returns>
public Document SendCommand(Type rootType, Document command)
{
- AuthenticateIfRequired();
return _connection.SendCommand(_serializationFactory, Name, rootType, command);
}
@@ -271,8 +270,6 @@ public T SendCommand<T>(string commandName)
/// <returns></returns>
public T SendCommand<T>(object command)
where T : CommandResultBase{
- AuthenticateIfRequired();
-
return _connection.SendCommand<T>(_serializationFactory, Name, typeof(T), command);
}
@@ -286,57 +283,7 @@ public T SendCommand<T>(object command)
public T SendCommand<T>(Type rootType, object command)
where T : CommandResultBase
{
- AuthenticateIfRequired();
-
return _connection.SendCommand<T>(_serializationFactory, Name, rootType, command);
}
-
- /// <summary>
- /// Authenticates the on first request.
- /// </summary>
- private void AuthenticateIfRequired(){
- if(_connection.IsAuthenticated)
- return;
-
- var builder = new MongoConnectionStringBuilder(_connection.ConnectionString);
-
- if(string.IsNullOrEmpty(builder.Username))
- return;
-
- var document = new Document().Add("getnonce", 1.0);
- var nonceResult = _connection.SendCommand(_serializationFactory, Name, typeof(Document), document);
- var nonce = (String)nonceResult["nonce"];
-
- if(nonce == null)
- throw new MongoException("Error retrieving nonce", null);
-
- var pwd = Hash(builder.Username + ":mongo:" + builder.Password);
- var auth = new Document{
- {"authenticate", 1.0},
- {"user", builder.Username},
- {"nonce", nonce},
- {"key", Hash(nonce + builder.Username + pwd)}
- };
- try{
- _connection.SendCommand(_serializationFactory, Name, typeof(Document), auth);
- }
- catch(MongoCommandException exception){
- //Todo: use custom exception?
- throw new MongoException("Authentication faild for " + builder.Username, exception);
- }
-
- _connection.MaskAuthenticated();
- }
-
- /// <summary>
- /// Hashes the specified text.
- /// </summary>
- /// <param name = "text">The text.</param>
- /// <returns></returns>
- internal static string Hash(string text){
- var md5 = MD5.Create();
- var hash = md5.ComputeHash(Encoding.Default.GetBytes(text));
- return BitConverter.ToString(hash).Replace("-", "").ToLower();
- }
}
}
View
6 MongoDBDriver/MongoSymbol.cs
@@ -26,10 +26,8 @@ public struct MongoSymbol : IEquatable<MongoSymbol>, IEquatable<String>, ICompar
/// <param name="value">The value.</param>
public MongoSymbol(string value)
: this(){
- if(string.IsNullOrEmpty(value))
- throw new ArgumentNullException("value");
-
- Value = String.Intern(value);
+ if(!string.IsNullOrEmpty(value))
+ Value = String.Intern(value);
}
/// <summary>
View
24 MongoDBDriver/Util/MongoHash.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace MongoDB.Driver.Util
+{
+ /// <summary>
+ ///
+ /// </summary>
+ internal static class MongoHash
+ {
+ /// <summary>
+ /// Generate a hash for the specified text.
+ /// </summary>
+ /// <param name="text">The text.</param>
+ /// <returns></returns>
+ public static string Generate(string text)
+ {
+ var md5 = MD5.Create();
+ var hash = md5.ComputeHash(Encoding.Default.GetBytes(text));
+ return BitConverter.ToString(hash).Replace("-", "").ToLower();
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.