2727using Xunit ;
2828using MongoDB . Driver . Core . Connections ;
2929using MongoDB . Bson . TestHelpers . XunitExtensions ;
30+ using System . Linq ;
3031
3132namespace MongoDB . Driver . Core . Authentication
3233{
@@ -49,19 +50,21 @@ public class ScramSha256AuthenticatorTests
4950
5051 /*
5152 * 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"
5354 * C: n,,n=user,r=rOprNGfwEbeRWgbNEkqO
5455 * S: r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,s=W22ZaJ0SNY7soEsUEjb6gQ==,i=4096
5556 * C: c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=
5657 * S: v=6rriTRBi23WpRR/wtup+mMhUZUn/dB5nLTJRsjl95G4=
5758 */
5859
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 =
6162 $ "r={ _clientNonce } { _serverNonce } ,s={ _serverSalt } ,i={ _iterationCount } ";
62- private static readonly string _clientRequest2 =
63+ private static readonly string __clientRequest2 =
6364 $ "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 = "" ;
6568
6669 private static void Authenticate (
6770 ScramSha256Authenticator authenticator ,
@@ -140,7 +143,7 @@ public void Authenticate_should_throw_when_server_provides_invalid_r_value(
140143 {
141144 var randomStringGenerator = new ConstantRandomStringGenerator ( _clientNonce ) ;
142145 var subject = new ScramSha256Authenticator ( __credential , randomStringGenerator ) ;
143- var poisonedSaslStart = PoisonSaslMessage ( message : _clientRequest1 , poison : "bluePill" ) ;
146+ var poisonedSaslStart = PoisonSaslMessage ( message : __clientRequest1 , poison : "bluePill" ) ;
144147 var poisonedSaslStartReply = CreateSaslStartReply ( poisonedSaslStart , _serverNonce , _serverSalt , _iterationCount ) ;
145148 var poisonedSaslStartReplyMessage = MessageHelper . BuildReply ( RawBsonDocumentHelper . FromJson (
146149 @"{conversationId: 1, " +
@@ -168,17 +171,17 @@ public void Authenticate_should_throw_when_server_provides_invalid_serverSignatu
168171 var randomStringGenerator = new ConstantRandomStringGenerator ( _clientNonce ) ;
169172 var subject = new ScramSha256Authenticator ( __credential , randomStringGenerator ) ;
170173
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" ) ;
173176 var saslStartReplyMessage = MessageHelper . BuildReply ( RawBsonDocumentHelper . FromJson (
174177 @"{conversationId: 1, " +
175178 $ " payload: BinData(0,\" { ToUtf8Base64 ( saslStartReply ) } \" )," +
176- @" done: false,
179+ @" done: false,
177180 ok: 1}" ) ) ;
178181 var poisonedSaslContinueReplyMessage = MessageHelper . BuildReply ( RawBsonDocumentHelper . FromJson (
179182 @"{conversationId: 1, " +
180183 $ " payload: BinData(0,\" { ToUtf8Base64 ( poisonedSaslContinueReply ) } \" )," +
181- @" done: true,
184+ @" done: true,
182185 ok: 1}" ) ) ;
183186
184187 var connection = new MockConnection ( __serverId ) ;
@@ -203,25 +206,35 @@ public void Authenticate_should_throw_when_server_provides_invalid_serverSignatu
203206 [ Theory ]
204207 [ ParameterAttributeData ]
205208 public void Authenticate_should_not_throw_when_authentication_succeeds(
209+ [ Values ( false , true ) ] bool useLongAuthentication,
206210 [ Values ( false , true ) ] bool async)
207211 {
208212 var randomStringGenerator = new ConstantRandomStringGenerator ( _clientNonce ) ;
209213 var subject = new ScramSha256Authenticator ( __credential , randomStringGenerator ) ;
210214
211215 var saslStartReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
212216 @"{conversationId: 1," +
213- $ " payload: BinData(0,\" { ToUtf8Base64 ( _serverResponse1 ) } \" )," +
214- @" done: false,
217+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverResponse1 ) } \" )," +
218+ @" done: false,
215219 ok: 1}" ) ) ;
216220 var saslContinueReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
217221 @"{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,
220229 ok: 1}" ) ) ;
221230
222231 var connection = new MockConnection( __serverId ) ;
223232 connection. EnqueueReplyMessage ( saslStartReply ) ;
224233 connection. EnqueueReplyMessage ( saslContinueReply ) ;
234+ if ( useLongAuthentication )
235+ {
236+ connection. EnqueueReplyMessage ( saslLastStepReply ) ;
237+ }
225238
226239 var expectedRequestId = RequestMessage. CurrentGlobalRequestId + 1 ;
227240
@@ -237,36 +250,55 @@ public void Authenticate_should_not_throw_when_authentication_succeeds(
237250
238251 var exception = Record . Exception ( act ) ;
239252 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 ( ) ;
241258
242259 var sentMessages = MessageHelper. TranslateMessagesToBsonDocuments ( connection . GetSentMessages ( ) ) ;
243- sentMessages. Count . Should ( ) . Be ( 2 ) ;
260+ sentMessages. Count . Should ( ) . Be ( expectedSentMessageCount ) ;
244261
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+ }
249267
250268 sentMessages[ 0 ] . Should ( ) . Be (
251269 @"{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,
258276 mechanism: ""SCRAM-SHA-256""," +
259- $ " payload: new BinData(0, \" { ToUtf8Base64 ( _clientRequest1 ) } \" )}}}}") ;
277+ $ " payload: new BinData(0, \" { ToUtf8Base64 ( __clientRequest1 ) } \" )" +
278+ @" options: { skipEmptyExchange: true }}}" ) ;
260279 sentMessages[ 1 ] . Should ( ) . Be (
261280 @"{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,
268287 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+ }
270302 }
271303
272304 [ Theory ]
@@ -279,12 +311,12 @@ public void Authenticate_should_use_cache(
279311
280312 var saslStartReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
281313 @"{conversationId: 1," +
282- $ " payload: BinData(0,\" { ToUtf8Base64 ( _serverResponse1 ) } \" )," +
314+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverResponse1 ) } \" )," +
283315 @" done: false,
284316 ok: 1}" ) ) ;
285317 var saslContinueReply = MessageHelper. BuildReply < RawBsonDocument > ( RawBsonDocumentHelper . FromJson (
286318 @"{conversationId: 1," +
287- $ " payload: BinData(0,\" { ToUtf8Base64 ( _serverReponse2 ) } \" )," +
319+ $ " payload: BinData(0,\" { ToUtf8Base64 ( __serverResponse2 ) } \" )," +
288320 @" done: true,
289321 ok: 1}" ) ) ;
290322
0 commit comments