27
27
using Xunit ;
28
28
using MongoDB . Driver . Core . Connections ;
29
29
using MongoDB . Bson . TestHelpers . XunitExtensions ;
30
+ using System . Linq ;
30
31
31
32
namespace MongoDB . Driver . Core . Authentication
32
33
{
@@ -49,19 +50,21 @@ public class ScramSha256AuthenticatorTests
49
50
50
51
/*
51
52
* This is a simple example of a SCRAM-SHA-256 authentication exchange. The username
52
- * 'user' and password 'pencil' are being used, with a client nonce of "rOprNGfwEbeRWgbNEkqO"
53
+ * 'user' and password 'pencil' are being used, with a client nonce of "rOprNGfwEbeRWgbNEkqO"
53
54
* C: n,,n=user,r=rOprNGfwEbeRWgbNEkqO
54
55
* S: r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096
55
56
* C: c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=
56
57
* S: v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4=
57
58
*/
58
59
59
- private static readonly string _clientRequest1 = $ "n,,n=user,r={ _clientNonce } ";
60
- private static readonly string _serverResponse1 =
60
+ private static readonly string __clientRequest1 = $ "n,,n=user,r={ _clientNonce } ";
61
+ private static readonly string __serverResponse1 =
61
62
$ "r={ _clientNonce } { _serverNonce } ,s={ _serverSalt } ,i={ _iterationCount } ";
62
- private static readonly string _clientRequest2 =
63
+ private static readonly string __clientRequest2 =
63
64
$ "c=biws,r={ _clientNonce } { _serverNonce } ,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=";
64
- private static readonly string _serverReponse2 = "v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4=" ;
65
+ private static readonly string __serverResponse2 = "v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4=" ;
66
+ private static readonly string __clientOptionalFinalRequest = "" ;
67
+ private static readonly string __serverOptionalFinalResponse = "" ;
65
68
66
69
private static void Authenticate (
67
70
ScramSha256Authenticator authenticator ,
@@ -140,7 +143,7 @@ public void Authenticate_should_throw_when_server_provides_invalid_r_value(
140
143
{
141
144
var randomStringGenerator = new ConstantRandomStringGenerator ( _clientNonce ) ;
142
145
var subject = new ScramSha256Authenticator ( __credential , randomStringGenerator ) ;
143
- var poisonedSaslStart = PoisonSaslMessage ( message : _clientRequest1 , poison : "bluePill" ) ;
146
+ var poisonedSaslStart = PoisonSaslMessage ( message : __clientRequest1 , poison : "bluePill" ) ;
144
147
var poisonedSaslStartReply = CreateSaslStartReply ( poisonedSaslStart , _serverNonce , _serverSalt , _iterationCount ) ;
145
148
var poisonedSaslStartReplyMessage = MessageHelper . BuildReply ( RawBsonDocumentHelper . FromJson (
146
149
@"{conversationId: 1, " +
@@ -168,17 +171,17 @@ public void Authenticate_should_throw_when_server_provides_invalid_serverSignatu
168
171
var randomStringGenerator = new ConstantRandomStringGenerator ( _clientNonce ) ;
169
172
var subject = new ScramSha256Authenticator ( __credential , randomStringGenerator ) ;
170
173
171
- var saslStartReply = CreateSaslStartReply ( _clientRequest1 , _serverNonce , _serverSalt , _iterationCount ) ;
172
- var poisonedSaslContinueReply = PoisonSaslMessage ( message : _serverReponse2 , poison : "redApple" ) ;
174
+ var saslStartReply = CreateSaslStartReply ( __clientRequest1 , _serverNonce , _serverSalt , _iterationCount ) ;
175
+ var poisonedSaslContinueReply = PoisonSaslMessage ( message : __serverResponse2 , poison : "redApple" ) ;
173
176
var saslStartReplyMessage = MessageHelper . BuildReply ( RawBsonDocumentHelper . FromJson (
174
177
@"{conversationId: 1, " +
175
178
$ " payload: BinData(0,\" { ToUtf8Base64 ( saslStartReply ) } \" )," +
176
- @" done: false,
179
+ @" done: false,
177
180
ok: 1}" ) ) ;
178
181
var poisonedSaslContinueReplyMessage = MessageHelper . BuildReply ( RawBsonDocumentHelper . FromJson (
179
182
@"{conversationId: 1, " +
180
183
$ " payload: BinData(0,\" { ToUtf8Base64 ( poisonedSaslContinueReply ) } \" )," +
181
- @" done: true,
184
+ @" done: true,
182
185
ok: 1}" ) ) ;
183
186
184
187
var connection = new MockConnection ( __serverId ) ;
@@ -203,25 +206,35 @@ public void Authenticate_should_throw_when_server_provides_invalid_serverSignatu
203
206
[ Theory ]
204
207
[ ParameterAttributeData ]
205
208
public void Authenticate_should_not_throw_when_authentication_succeeds(
209
+ [ Values ( false , true ) ] bool useLongAuthentication,
206
210
[ Values ( false , true ) ] bool async)
207
211
{
208
212
var randomStringGenerator = new ConstantRandomStringGenerator ( _clientNonce ) ;
209
213
var subject = new ScramSha256Authenticator ( __credential , randomStringGenerator ) ;
210
214
211
215
var saslStartReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
212
216
@"{conversationId: 1," +
213
- $ " payload: BinData(0,\" { ToUtf8Base64 ( _serverResponse1 ) } \" )," +
214
- @" done: false,
217
+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverResponse1 ) } \" )," +
218
+ @" done: false,
215
219
ok: 1}" ) ) ;
216
220
var saslContinueReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
217
221
@"{conversationId: 1," +
218
- $ " payload: BinData(0,\" { ToUtf8Base64 ( _serverReponse2 ) } \" )," +
219
- @" done: true,
222
+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverResponse2 ) } \" )," +
223
+ $ " done: { new BsonBoolean ( ! useLongAuthentication ) } ," +
224
+ @" ok: 1}" ) ) ;
225
+ var saslLastStepReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
226
+ @"{conversationId: 1," +
227
+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverOptionalFinalResponse ) } \" )," +
228
+ @" done: true,
220
229
ok: 1}" ) ) ;
221
230
222
231
var connection = new MockConnection( __serverId ) ;
223
232
connection. EnqueueReplyMessage ( saslStartReply ) ;
224
233
connection. EnqueueReplyMessage ( saslContinueReply ) ;
234
+ if ( useLongAuthentication )
235
+ {
236
+ connection. EnqueueReplyMessage ( saslLastStepReply ) ;
237
+ }
225
238
226
239
var expectedRequestId = RequestMessage. CurrentGlobalRequestId + 1 ;
227
240
@@ -237,36 +250,55 @@ public void Authenticate_should_not_throw_when_authentication_succeeds(
237
250
238
251
var exception = Record . Exception ( act ) ;
239
252
exception. Should ( ) . BeNull ( ) ;
240
- SpinWait. SpinUntil ( ( ) => connection . GetSentMessages ( ) . Count >= 2 , TimeSpan . FromSeconds ( 5 ) ) . Should ( ) . BeTrue ( ) ;
253
+ var expectedSentMessageCount = useLongAuthentication ? 3 : 2 ;
254
+ SpinWait. SpinUntil (
255
+ ( ) => connection . GetSentMessages ( ) . Count >= expectedSentMessageCount ,
256
+ TimeSpan . FromSeconds ( 5 )
257
+ ) . Should ( ) . BeTrue ( ) ;
241
258
242
259
var sentMessages = MessageHelper. TranslateMessagesToBsonDocuments ( connection . GetSentMessages ( ) ) ;
243
- sentMessages. Count . Should ( ) . Be ( 2 ) ;
260
+ sentMessages. Count . Should ( ) . Be ( expectedSentMessageCount ) ;
244
261
245
- var actualRequestId0 = sentMessages[ 0 ] [ "requestId" ] . AsInt32 ;
246
- var actualRequestId1 = sentMessages [ 1 ] [ "requestId" ] . AsInt32 ;
247
- actualRequestId0. Should ( ) . BeInRange ( expectedRequestId , expectedRequestId + 10 ) ;
248
- actualRequestId1. Should ( ) . BeInRange ( actualRequestId0 + 1 , actualRequestId0 + 11 ) ;
262
+ var actualRequestIds = sentMessages. Select ( m => m [ "requestId" ] . AsInt32 ) . ToList ( ) ;
263
+ for ( var i = 0 ; i != actualRequestIds . Count ; ++ i)
264
+ {
265
+ actualRequestIds[ i ] . Should ( ) . BeInRange ( expectedRequestId + i , expectedRequestId + 10 + i ) ;
266
+ }
249
267
250
268
sentMessages[ 0 ] . Should ( ) . Be (
251
269
@"{opcode: ""query""," +
252
- $ " requestId: { actualRequestId0 } ," +
253
- @" database: ""source"",
254
- collection: ""$cmd"",
255
- batchSize: -1,
256
- slaveOk: true,
257
- query: {saslStart: 1,
270
+ $ " requestId: { actualRequestIds [ 0 ] } ," +
271
+ @" database: ""source"",
272
+ collection: ""$cmd"",
273
+ batchSize: -1,
274
+ slaveOk: true,
275
+ query: {saslStart: 1,
258
276
mechanism: ""SCRAM-SHA-256""," +
259
- $ " payload: new BinData(0, \" { ToUtf8Base64 ( _clientRequest1 ) } \" )}}}}") ;
277
+ $ " payload: new BinData(0, \" { ToUtf8Base64 ( __clientRequest1 ) } \" )" +
278
+ @" options: { skipEmptyExchange: true }}}" ) ;
260
279
sentMessages[ 1 ] . Should ( ) . Be (
261
280
@"{opcode: ""query""," +
262
- $ " requestId: { actualRequestId1 } ," +
263
- @" database: ""source"",
264
- collection: ""$cmd"",
265
- batchSize: -1,
266
- slaveOk: true,
267
- query: {saslContinue: 1,
281
+ $ " requestId: { actualRequestIds [ 1 ] } ," +
282
+ @" database: ""source"",
283
+ collection: ""$cmd"",
284
+ batchSize: -1,
285
+ slaveOk: true,
286
+ query: {saslContinue: 1,
268
287
conversationId: 1, " +
269
- $ " payload: new BinData(0, \" { ToUtf8Base64 ( _clientRequest2 ) } \" )}}}}") ;
288
+ $ " payload: new BinData(0, \" { ToUtf8Base64 ( __clientRequest2 ) } \" )}}}}") ;
289
+ if ( useLongAuthentication )
290
+ {
291
+ sentMessages[ 2 ] . Should ( ) . Be (
292
+ @"{opcode: ""query""," +
293
+ $ " requestId: { actualRequestIds [ 2 ] } ," +
294
+ @" database: ""source"",
295
+ collection: ""$cmd"",
296
+ batchSize: -1,
297
+ slaveOk: true,
298
+ query: {saslContinue: 1,
299
+ conversationId: 1, " +
300
+ $ " payload: new BinData(0, \" { ToUtf8Base64 ( __clientOptionalFinalRequest ) } \" )}}}}") ;
301
+ }
270
302
}
271
303
272
304
[ Theory ]
@@ -279,12 +311,12 @@ public void Authenticate_should_use_cache(
279
311
280
312
var saslStartReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
281
313
@"{conversationId: 1," +
282
- $ " payload: BinData(0,\" { ToUtf8Base64 ( _serverResponse1 ) } \" )," +
314
+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverResponse1 ) } \" )," +
283
315
@" done: false,
284
316
ok: 1}" ) ) ;
285
317
var saslContinueReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
286
318
@"{conversationId: 1," +
287
- $ " payload: BinData(0,\" { ToUtf8Base64 ( _serverReponse2 ) } \" )," +
319
+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverResponse2 ) } \" )," +
288
320
@" done: true,
289
321
ok: 1}" ) ) ;
290
322
0 commit comments