1
1
import { expect } from 'chai' ;
2
- import { satisfies } from 'semver' ;
3
2
import * as sinon from 'sinon' ;
4
3
5
4
import { Connection , LEGACY_HELLO_COMMAND , type MongoClient , ScramSHA256 } from '../../mongodb' ;
@@ -8,20 +7,16 @@ function makeConnectionString(config, username, password) {
8
7
return `mongodb://${ username } :${ password } @${ config . host } :${ config . port } /admin?` ;
9
8
}
10
9
11
- describe ( 'Authentication Spec Prose Tests' , function ( ) {
12
- beforeEach ( function ( ) {
13
- // todo(NODE-5631): fix tests to run in load balancer mode.
14
- if (
15
- process . env . AUTH === 'noauth' ||
16
- process . env . LOAD_BALANCER ||
17
- ! satisfies ( this . configuration . version , '>=3.7.3' )
18
- ) {
19
- this . currentTest . skipReason =
20
- 'Skipping SCRAM tests when auth is disabled, load balanced mode, or server < 3.7.3.' ;
21
- this . currentTest . skip ( ) ;
22
- }
23
- } ) ;
10
+ const metadata : MongoDBMetadataUI = {
11
+ requires : {
12
+ auth : 'enabled' ,
13
+ mongodb : '>=3.7.3' ,
14
+ predicate : ( ) =>
15
+ process . env . LOAD_BALANCER ? 'TODO(NODE-5631): fix tests to run in load balancer mode.' : true
16
+ }
17
+ } ;
24
18
19
+ describe ( 'Authentication Spec Prose Tests' , function ( ) {
25
20
describe ( 'SCRAM-SHA-256 and mechanism negotiation' , ( ) => {
26
21
describe ( 'Steps 1-3' , function ( ) {
27
22
const userMap = {
@@ -82,9 +77,10 @@ describe('Authentication Spec Prose Tests', function () {
82
77
*/
83
78
for ( const user of users ) {
84
79
for ( const mechanism of user . mechanisms ) {
85
- it ( `authenticates ${ user . description } when explicitly specifying ${ mechanism } ` , {
86
- metadata : { requires : { mongodb : '>=3.7.3' } } ,
87
- test : async function ( ) {
80
+ it (
81
+ `authenticates ${ user . description } when explicitly specifying ${ mechanism } via client options` ,
82
+ metadata ,
83
+ async function ( ) {
88
84
const options = {
89
85
auth : {
90
86
username : user . username ,
@@ -95,15 +91,19 @@ describe('Authentication Spec Prose Tests', function () {
95
91
} ;
96
92
97
93
const client = this . configuration . newClient ( { } , options ) ;
98
- const stats = await client . db ( 'test' ) . stats ( ) ;
99
- expect ( stats ) . to . exist ;
100
- await client . close ( ) ;
94
+ try {
95
+ const stats = await client . db ( 'test' ) . stats ( ) ;
96
+ expect ( stats ) . to . exist ;
97
+ } finally {
98
+ await client . close ( ) ;
99
+ }
101
100
}
102
- } ) ;
101
+ ) ;
103
102
104
- it ( `authenticates ${ user . description } when explicitly specifying ${ mechanism } in url` , {
105
- metadata : { requires : { mongodb : '>=3.7.3' } } ,
106
- test : async function ( ) {
103
+ it (
104
+ `authenticates ${ user . description } when explicitly specifying ${ mechanism } in url` ,
105
+ metadata ,
106
+ async function ( ) {
107
107
const username = encodeURIComponent ( user . username ) ;
108
108
const password = encodeURIComponent ( user . password ) ;
109
109
@@ -114,16 +114,20 @@ describe('Authentication Spec Prose Tests', function () {
114
114
) } authMechanism=${ mechanism } `;
115
115
116
116
const client = this . configuration . newClient ( url ) ;
117
- const stats = await client . db ( 'test' ) . stats ( ) ;
118
- expect ( stats ) . to . exist ;
119
- await client . close ( ) ;
117
+ try {
118
+ const stats = await client . db ( 'test' ) . stats ( ) ;
119
+ expect ( stats ) . to . exist ;
120
+ } finally {
121
+ await client . close ( ) ;
122
+ }
120
123
}
121
- } ) ;
124
+ ) ;
122
125
}
123
126
124
- it ( `authenticates ${ user . description } using mechanism negotiaton` , {
125
- metadata : { requires : { mongodb : '>=3.7.3' } } ,
126
- test : async function ( ) {
127
+ it (
128
+ `authenticates ${ user . description } using mechanism negotiaton` ,
129
+ metadata ,
130
+ async function ( ) {
127
131
const options = {
128
132
auth : {
129
133
username : user . username ,
@@ -133,25 +137,32 @@ describe('Authentication Spec Prose Tests', function () {
133
137
} ;
134
138
135
139
const client = this . configuration . newClient ( { } , options ) ;
136
- const stats = await client . db ( 'test' ) . stats ( ) ;
137
- expect ( stats ) . to . exist ;
138
- await client . close ( ) ;
140
+ try {
141
+ const stats = await client . db ( 'test' ) . stats ( ) ;
142
+ expect ( stats ) . to . exist ;
143
+ } finally {
144
+ await client . close ( ) ;
145
+ }
139
146
}
140
- } ) ;
147
+ ) ;
141
148
142
- it ( `authenticates ${ user . description } using mechanism negotiaton and url` , {
143
- metadata : { requires : { mongodb : '>=3.7.3' } } ,
144
- test : async function ( ) {
149
+ it (
150
+ `authenticates ${ user . description } using mechanism negotiaton and url` ,
151
+ metadata ,
152
+ async function ( ) {
145
153
const username = encodeURIComponent ( user . username ) ;
146
154
const password = encodeURIComponent ( user . password ) ;
147
155
const url = makeConnectionString ( this . configuration , username , password ) ;
148
156
149
157
const client = this . configuration . newClient ( url ) ;
150
- const stats = await client . db ( 'test' ) . stats ( ) ;
151
- expect ( stats ) . to . exist ;
152
- await client . close ( ) ;
158
+ try {
159
+ const stats = await client . db ( 'test' ) . stats ( ) ;
160
+ expect ( stats ) . to . exist ;
161
+ } finally {
162
+ await client . close ( ) ;
163
+ }
153
164
}
154
- } ) ;
165
+ ) ;
155
166
}
156
167
157
168
/**
@@ -161,9 +172,10 @@ describe('Authentication Spec Prose Tests', function () {
161
172
* analysis, etc.
162
173
* todo(NODE-5629): Test passes locally but will fail on CI runs.
163
174
*/
164
- it . skip ( 'selects SCRAM-SHA-256 for a user that supports both auth mechanisms' , {
165
- metadata : { requires : { mongodb : '>=3.7.3' } } ,
166
- test : async function ( ) {
175
+ it . skip (
176
+ 'selects SCRAM-SHA-256 for a user that supports both auth mechanisms' ,
177
+ metadata ,
178
+ async function ( ) {
167
179
const options = {
168
180
auth : {
169
181
username : userMap . both . username ,
@@ -173,24 +185,27 @@ describe('Authentication Spec Prose Tests', function () {
173
185
} ;
174
186
175
187
const spy = sinon . spy ( ScramSHA256 . prototype , 'auth' ) ;
176
-
177
188
const client = this . configuration . newClient ( { } , options ) ;
178
- const stats = await client . db ( 'test' ) . stats ( ) ;
179
- expect ( stats ) . to . exist ;
180
- expect ( spy . called ) . to . equal ( true ) ;
181
- sinon . restore ( ) ;
182
- await client . close ( ) ;
189
+ try {
190
+ const stats = await client . db ( 'test' ) . stats ( ) ;
191
+ expect ( stats ) . to . exist ;
192
+ expect ( spy . called ) . to . equal ( true ) ;
193
+ } finally {
194
+ sinon . restore ( ) ;
195
+ await client . close ( ) ;
196
+ }
183
197
}
184
- } ) ;
198
+ ) . skipReason = 'todo(NODE-5629): Test passes locally but will fail on CI runs.' ;
185
199
186
200
/**
187
201
* Step 3
188
202
* For test users that support only one mechanism, verify that explictly specifying
189
203
* the other mechanism fails.
190
204
*/
191
- it ( 'fails to connect if incorrect auth mechanism is explicitly specified' , {
192
- metadata : { requires : { mongodb : '>=3.7.3' } } ,
193
- test : async function ( ) {
205
+ it (
206
+ 'fails to connect if incorrect auth mechanism is explicitly specified' ,
207
+ metadata ,
208
+ async function ( ) {
194
209
const options = {
195
210
auth : {
196
211
username : userMap . sha256 . username ,
@@ -208,7 +223,7 @@ describe('Authentication Spec Prose Tests', function () {
208
223
expect ( error . message ) . to . match ( / A u t h e n t i c a t i o n f a i l e d | S C R A M / ) ;
209
224
await client . close ( ) ;
210
225
}
211
- } ) ;
226
+ ) ;
212
227
213
228
/*
214
229
* Step 3
@@ -220,12 +235,12 @@ describe('Authentication Spec Prose Tests', function () {
220
235
* authentication errors, not as a network or database command error on the ``hello``
221
236
* or legacy hello commands themselves.)
222
237
*/
223
- it ( 'fails for a nonexistent username with same error type as bad password' , {
224
- metadata : { requires : { mongodb : '>=3.7.3' } } ,
225
- test : async function ( ) {
238
+ it (
239
+ 'fails for a nonexistent username with same error type as bad password' ,
240
+ metadata ,
241
+ async function ( ) {
226
242
const noUsernameOptions = {
227
243
auth : {
228
- username : 'roth' ,
229
244
password : 'pencil'
230
245
} ,
231
246
authSource : 'admin'
@@ -239,26 +254,31 @@ describe('Authentication Spec Prose Tests', function () {
239
254
authSource : 'admin'
240
255
} ;
241
256
242
- const noUserClient = this . configuration . newClient ( { } , noUsernameOptions ) ;
257
+ try {
258
+ this . configuration . newClient ( { } , noUsernameOptions ) ;
259
+ expect . fail (
260
+ 'Creating a new client with a password and no username must fail validation.'
261
+ ) ;
262
+ } catch ( noUserError ) {
263
+ // NOTE: This prose test fails Node's validation of the credentials object - a username
264
+ // MUST always be provided but it satisfies the test requirement of not getting a
265
+ // network or command error on the handshake.
266
+ expect ( noUserError ) . to . match ( / u s e r n a m e / ) ;
267
+ }
243
268
const badPasswordClient = this . configuration . newClient ( { } , badPasswordOptions ) ;
244
- const noUserError = await noUserClient
245
- . db ( 'test' )
246
- . stats ( )
247
- . catch ( e => e ) ;
248
269
const badPasswordError = await badPasswordClient
249
270
. db ( 'test' )
250
271
. stats ( )
251
272
. catch ( e => e ) ;
252
- expect ( noUserError ) . to . match ( / A u t h e n t i c a t i o n f a i l e d / ) ;
253
273
expect ( badPasswordError ) . to . match ( / A u t h e n t i c a t i o n f a i l e d / ) ;
254
- await noUserClient . close ( ) ;
255
274
await badPasswordClient . close ( ) ;
256
275
}
257
- } ) ;
276
+ ) ;
258
277
259
- it ( 'should send speculativeAuthenticate on initial handshake on MongoDB 4.4+' , {
260
- metadata : { requires : { mongodb : '>=4.4' , topology : [ 'single' ] } } ,
261
- test : async function ( ) {
278
+ it (
279
+ 'sends speculativeAuthenticate on initial handshake on MongoDB 4.4+' ,
280
+ metadata ,
281
+ async function ( ) {
262
282
const options = {
263
283
auth : {
264
284
username : userMap . both . username ,
@@ -269,25 +289,28 @@ describe('Authentication Spec Prose Tests', function () {
269
289
270
290
const commandSpy = sinon . spy ( Connection . prototype , 'command' ) ;
271
291
const client = this . configuration . newClient ( { } , options ) ;
272
- await client . connect ( ) ;
273
- const calls = commandSpy
274
- . getCalls ( )
275
- . filter ( c => c . thisValue . id !== '<monitor>' ) // ignore all monitor connections
276
- . filter (
277
- c => c . args [ 1 ] [ process . env . MONGODB_API_VERSION ? 'hello' : LEGACY_HELLO_COMMAND ]
278
- ) ;
279
-
280
- expect ( calls ) . to . have . length ( 1 ) ;
281
- const handshakeDoc = calls [ 0 ] . args [ 1 ] ;
282
- expect ( handshakeDoc ) . to . have . property ( 'speculativeAuthenticate' ) ;
283
- sinon . restore ( ) ;
284
- await client . close ( ) ;
292
+ try {
293
+ await client . connect ( ) ;
294
+ const calls = commandSpy
295
+ . getCalls ( )
296
+ . filter ( c => c . thisValue . id !== '<monitor>' ) // ignore all monitor connections
297
+ . filter (
298
+ c => c . args [ 1 ] [ process . env . MONGODB_API_VERSION ? 'hello' : LEGACY_HELLO_COMMAND ]
299
+ ) ;
300
+
301
+ expect ( calls ) . to . have . length ( 1 ) ;
302
+ const handshakeDoc = calls [ 0 ] . args [ 1 ] ;
303
+ expect ( handshakeDoc ) . to . have . property ( 'speculativeAuthenticate' ) ;
304
+ } finally {
305
+ sinon . restore ( ) ;
306
+ await client . close ( ) ;
307
+ }
285
308
}
286
- } ) ;
309
+ ) ;
287
310
} ) ;
288
311
289
312
// todo(NODE-5621): fix the issue with unicode characters.
290
- describe . skip ( 'Step 4' , function ( ) {
313
+ describe ( 'Step 4' , function ( ) {
291
314
/**
292
315
* Step 4
293
316
* To test SASLprep behavior, create two users:
@@ -319,7 +342,7 @@ describe('Authentication Spec Prose Tests', function () {
319
342
}
320
343
] ;
321
344
322
- before ( async function ( ) {
345
+ beforeEach ( async function ( ) {
323
346
utilClient = this . configuration . newClient ( ) ;
324
347
const db = utilClient . db ( 'admin' ) ;
325
348
@@ -333,25 +356,22 @@ describe('Authentication Spec Prose Tests', function () {
333
356
await Promise . all ( createUserCommands . map ( cmd => db . command ( cmd ) ) ) ;
334
357
} ) ;
335
358
336
- after ( async function ( ) {
359
+ afterEach ( async function ( ) {
337
360
const db = utilClient . db ( 'admin' ) ;
338
361
await Promise . all ( users . map ( user => db . removeUser ( user . username ) ) ) ;
339
362
await utilClient ?. close ( ) ;
340
363
} ) ;
341
364
342
- [
365
+ for ( const { username , password } of [
343
366
{ username : 'IX' , password : 'IX' } ,
344
367
{ username : 'IX' , password : 'I\u00ADX' } ,
345
368
{ username : '\u2168' , password : 'IV' } ,
346
369
{ username : '\u2168' , password : 'I\u00ADV' }
347
- ] . forEach ( ( { username, password } ) => {
348
- it ( `logs in with username "${ username } " and password "${ password } "` , {
349
- metadata : {
350
- requires : {
351
- mongodb : '>=3.7.3'
352
- }
353
- } ,
354
- test : async function ( ) {
370
+ ] ) {
371
+ it . skip (
372
+ `logs in with username "${ username } " and password "${ password } "` ,
373
+ metadata ,
374
+ async function ( ) {
355
375
const options = {
356
376
auth : { username, password } ,
357
377
authSource : 'admin' ,
@@ -366,8 +386,8 @@ describe('Authentication Spec Prose Tests', function () {
366
386
await client . close ( ) ;
367
387
}
368
388
}
369
- } ) ;
370
- } ) ;
389
+ ) . skipReason = 'todo(NODE-5621): fix the issue with unicode characters.' ;
390
+ }
371
391
} ) ;
372
392
} ) ;
373
393
} ) ;
0 commit comments