14
14
*/
15
15
16
16
using System ;
17
- using System . Collections . Generic ;
18
17
using System . IO ;
19
18
using System . Net . Security ;
20
19
using System . Net . Sockets ;
21
20
using System . Security . Cryptography . X509Certificates ;
22
21
using MongoDB . Bson ;
23
22
using MongoDB . Bson . IO ;
24
23
using MongoDB . Bson . Serialization ;
24
+ using MongoDB . Driver . Communication ;
25
+ using MongoDB . Driver . Communication . Security ;
25
26
26
27
namespace MongoDB . Driver . Internal
27
28
{
@@ -61,16 +62,13 @@ public class MongoConnection
61
62
private DateTime _lastUsedAt ; // set every time the connection is Released
62
63
private int _messageCounter ;
63
64
private int _requestId ;
64
- private Dictionary < string , Authentication > _authentications = new Dictionary < string , Authentication > ( ) ;
65
65
66
66
// constructors
67
67
internal MongoConnection ( MongoConnectionPool connectionPool )
68
+ : this ( connectionPool . ServerInstance )
68
69
{
69
- _serverInstance = connectionPool . ServerInstance ;
70
70
_connectionPool = connectionPool ;
71
71
_generationId = connectionPool . GenerationId ;
72
- _createdAt = DateTime . UtcNow ;
73
- _state = MongoConnectionState . Initial ;
74
72
}
75
73
76
74
internal MongoConnection ( MongoServerInstance serverInstance )
@@ -147,138 +145,6 @@ public MongoConnectionState State
147
145
}
148
146
149
147
// internal methods
150
- internal void Authenticate ( string databaseName , MongoCredentials credentials )
151
- {
152
- if ( _state == MongoConnectionState . Closed ) { throw new InvalidOperationException ( "Connection is closed." ) ; }
153
- lock ( _connectionLock )
154
- {
155
- var nonceCommand = new CommandDocument ( "getnonce" , 1 ) ;
156
- var commandResult = RunCommand ( databaseName , QueryFlags . None , nonceCommand , false ) ;
157
- if ( ! commandResult . Ok )
158
- {
159
- throw new MongoAuthenticationException (
160
- "Error getting nonce for authentication." ,
161
- new MongoCommandException ( commandResult ) ) ;
162
- }
163
-
164
- var nonce = commandResult . Response [ "nonce" ] . AsString ;
165
- var passwordDigest = MongoUtils . Hash ( credentials . Username + ":mongo:" + credentials . Password ) ;
166
- var digest = MongoUtils . Hash ( nonce + credentials . Username + passwordDigest ) ;
167
- var authenticateCommand = new CommandDocument
168
- {
169
- { "authenticate" , 1 } ,
170
- { "user" , credentials . Username } ,
171
- { "nonce" , nonce } ,
172
- { "key" , digest }
173
- } ;
174
-
175
- commandResult = RunCommand ( databaseName , QueryFlags . None , authenticateCommand , false ) ;
176
- if ( ! commandResult . Ok )
177
- {
178
- var message = string . Format ( "Invalid credentials for database '{0}'." , databaseName ) ;
179
- throw new MongoAuthenticationException (
180
- message ,
181
- new MongoCommandException ( commandResult ) ) ;
182
- }
183
-
184
- var authentication = new Authentication ( credentials ) ;
185
- _authentications . Add ( databaseName , authentication ) ;
186
- }
187
- }
188
-
189
- // check whether the connection can be used with the given database (and credentials)
190
- // the following are the only valid authentication states for a connection:
191
- // 1. the connection is not authenticated against any database
192
- // 2. the connection has a single authentication against the admin database (with a particular set of credentials)
193
- // 3. the connection has one or more authentications against any databases other than admin
194
- // (with the restriction that a particular database can only be authenticated against once and therefore with only one set of credentials)
195
-
196
- // assume that IsAuthenticated was called first and returned false
197
- internal bool CanAuthenticate ( string databaseName , MongoCredentials credentials )
198
- {
199
- if ( _state == MongoConnectionState . Closed ) { throw new InvalidOperationException ( "Connection is closed." ) ; }
200
- if ( databaseName == null )
201
- {
202
- return true ;
203
- }
204
-
205
- if ( _authentications . Count == 0 )
206
- {
207
- // a connection with no existing authentications can authenticate anything
208
- return true ;
209
- }
210
- else
211
- {
212
- // a connection with existing authentications can't be used without credentials
213
- if ( credentials == null )
214
- {
215
- return false ;
216
- }
217
-
218
- // a connection with existing authentications can't be used with new admin credentials
219
- if ( credentials . Admin )
220
- {
221
- return false ;
222
- }
223
-
224
- // a connection with an existing authentication to the admin database can't be used with any other credentials
225
- if ( _authentications . ContainsKey ( "admin" ) )
226
- {
227
- return false ;
228
- }
229
-
230
- // a connection with an existing authentication to a database can't authenticate for the same database again
231
- if ( _authentications . ContainsKey ( databaseName ) )
232
- {
233
- return false ;
234
- }
235
-
236
- return true ;
237
- }
238
- }
239
-
240
- internal void CheckAuthentication ( string databaseName , MongoCredentials credentials )
241
- {
242
- if ( _state == MongoConnectionState . Closed ) { throw new InvalidOperationException ( "Connection is closed." ) ; }
243
- if ( credentials == null )
244
- {
245
- if ( _authentications . Count != 0 )
246
- {
247
- throw new InvalidOperationException ( "Connection requires credentials." ) ;
248
- }
249
- }
250
- else
251
- {
252
- var authenticationDatabaseName = credentials . Admin ? "admin" : databaseName ;
253
- Authentication authentication ;
254
- if ( _authentications . TryGetValue ( authenticationDatabaseName , out authentication ) )
255
- {
256
- if ( authentication . Credentials != credentials )
257
- {
258
- // this shouldn't happen because a connection would have been chosen from the connection pool only if it was viable
259
- if ( authenticationDatabaseName == "admin" )
260
- {
261
- throw new MongoInternalException ( "Connection already authenticated to the admin database with different credentials." ) ;
262
- }
263
- else
264
- {
265
- throw new MongoInternalException ( "Connection already authenticated to the database with different credentials." ) ;
266
- }
267
- }
268
- authentication . LastUsed = DateTime . UtcNow ;
269
- }
270
- else
271
- {
272
- if ( authenticationDatabaseName == "admin" && _authentications . Count != 0 )
273
- {
274
- // this shouldn't happen because a connection would have been chosen from the connection pool only if it was viable
275
- throw new MongoInternalException ( "The connection cannot be authenticated against the admin database because it is already authenticated against other databases." ) ;
276
- }
277
- Authenticate ( authenticationDatabaseName , credentials ) ;
278
- }
279
- }
280
- }
281
-
282
148
internal void Close ( )
283
149
{
284
150
lock ( _connectionLock )
@@ -305,61 +171,13 @@ internal void Close()
305
171
}
306
172
}
307
173
308
- internal bool IsAuthenticated ( string databaseName , MongoCredentials credentials )
309
- {
310
- if ( _state == MongoConnectionState . Closed ) { throw new InvalidOperationException ( "Connection is closed." ) ; }
311
- if ( databaseName == null )
312
- {
313
- return true ;
314
- }
315
-
316
- lock ( _connectionLock )
317
- {
318
- if ( credentials == null )
319
- {
320
- return _authentications . Count == 0 ;
321
- }
322
- else
323
- {
324
- var authenticationDatabaseName = credentials . Admin ? "admin" : databaseName ;
325
- Authentication authentication ;
326
- if ( _authentications . TryGetValue ( authenticationDatabaseName , out authentication ) )
327
- {
328
- return credentials == authentication . Credentials ;
329
- }
330
- else
331
- {
332
- return false ;
333
- }
334
- }
335
- }
336
- }
337
-
338
174
internal bool IsExpired ( )
339
175
{
340
176
var now = DateTime . UtcNow ;
341
177
return now > _createdAt + _serverInstance . Settings . MaxConnectionLifeTime
342
178
|| now > _lastUsedAt + _serverInstance . Settings . MaxConnectionIdleTime ;
343
179
}
344
180
345
- internal void Logout ( string databaseName )
346
- {
347
- if ( _state == MongoConnectionState . Closed ) { throw new InvalidOperationException ( "Connection is closed." ) ; }
348
- lock ( _connectionLock )
349
- {
350
- var logoutCommand = new CommandDocument ( "logout" , 1 ) ;
351
- var commandResult = RunCommand ( databaseName , QueryFlags . None , logoutCommand , false ) ;
352
- if ( ! commandResult . Ok )
353
- {
354
- throw new MongoAuthenticationException (
355
- "Error logging off." ,
356
- new MongoCommandException ( commandResult ) ) ;
357
- }
358
-
359
- _authentications . Remove ( databaseName ) ;
360
- }
361
- }
362
-
363
181
internal void Open ( )
364
182
{
365
183
if ( _state != MongoConnectionState . Initial )
@@ -405,6 +223,9 @@ internal void Open()
405
223
_tcpClient = tcpClient ;
406
224
_stream = stream ;
407
225
_state = MongoConnectionState . Open ;
226
+
227
+ new Authenticator ( this , _serverInstance . Settings . CredentialsStore )
228
+ . Authenticate ( ) ;
408
229
}
409
230
410
231
// this is a low level method that doesn't require a MongoServer
@@ -629,33 +450,5 @@ private HandleExceptionAction DetermineAction(Exception ex)
629
450
630
451
return HandleExceptionAction . CloseConnection ; // this should always be the default action
631
452
}
632
-
633
- // private nested classes
634
- // keeps track of what credentials were used with a given database
635
- // and when that database was last used on this connection
636
- private class Authentication
637
- {
638
- // private fields
639
- private MongoCredentials _credentials ;
640
- private DateTime _lastUsed ;
641
-
642
- // constructors
643
- public Authentication ( MongoCredentials credentials )
644
- {
645
- _credentials = credentials ;
646
- _lastUsed = DateTime . UtcNow ;
647
- }
648
-
649
- public MongoCredentials Credentials
650
- {
651
- get { return _credentials ; }
652
- }
653
-
654
- public DateTime LastUsed
655
- {
656
- get { return _lastUsed ; }
657
- set { _lastUsed = value ; }
658
- }
659
- }
660
453
}
661
454
}
0 commit comments