Skip to content

Commit 60eea59

Browse files
authored
Handle mongodb auth errors that may occur after running the server for a while (#4576)
1 parent 9db63a4 commit 60eea59

File tree

1 file changed

+66
-28
lines changed

1 file changed

+66
-28
lines changed

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 66 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import Parse from 'parse/node';
2323
// @flow-disable-next
2424
import _ from 'lodash';
2525
import defaults from '../../../defaults';
26+
import logger from '../../../logger';
2627

2728
// @flow-disable-next
2829
const mongodb = require('mongodb');
@@ -160,6 +161,16 @@ export class MongoStorageAdapter implements StorageAdapter {
160161
return this.connectionPromise;
161162
}
162163

164+
handleError<T>(error: ?Error): Promise<T> {
165+
if (error && error.code === 13) { // Unauthorized error
166+
delete this.client;
167+
delete this.database;
168+
delete this.connectionPromise;
169+
logger.error('Received unauthorized error', { error: error });
170+
}
171+
throw error;
172+
}
173+
163174
handleShutdown() {
164175
if (!this.client) {
165176
return;
@@ -170,7 +181,8 @@ export class MongoStorageAdapter implements StorageAdapter {
170181
_adaptiveCollection(name: string) {
171182
return this.connect()
172183
.then(() => this.database.collection(this._collectionPrefix + name))
173-
.then(rawCollection => new MongoCollection(rawCollection));
184+
.then(rawCollection => new MongoCollection(rawCollection))
185+
.catch(err => this.handleError(err));
174186
}
175187

176188
_schemaCollection(): Promise<MongoSchemaCollection> {
@@ -184,14 +196,14 @@ export class MongoStorageAdapter implements StorageAdapter {
184196
return this.database.listCollections({ name: this._collectionPrefix + name }).toArray();
185197
}).then(collections => {
186198
return collections.length > 0;
187-
});
199+
}).catch(err => this.handleError(err));
188200
}
189201

190202
setClassLevelPermissions(className: string, CLPs: any): Promise<void> {
191203
return this._schemaCollection()
192204
.then(schemaCollection => schemaCollection.updateSchema(className, {
193205
$set: { '_metadata.class_permissions': CLPs }
194-
}));
206+
})).catch(err => this.handleError(err));
195207
}
196208

197209
setIndexesWithSchemaFormat(className: string, submittedIndexes: any, existingIndexes: any = {}, fields: any): Promise<void> {
@@ -237,7 +249,8 @@ export class MongoStorageAdapter implements StorageAdapter {
237249
.then(() => this._schemaCollection())
238250
.then(schemaCollection => schemaCollection.updateSchema(className, {
239251
$set: { '_metadata.indexes': existingIndexes }
240-
}));
252+
}))
253+
.catch(err => this.handleError(err));
241254
}
242255

243256
setIndexesFromMongo(className: string) {
@@ -257,10 +270,12 @@ export class MongoStorageAdapter implements StorageAdapter {
257270
.then(schemaCollection => schemaCollection.updateSchema(className, {
258271
$set: { '_metadata.indexes': indexes }
259272
}));
260-
}).catch(() => {
261-
// Ignore if collection not found
262-
return Promise.resolve();
263-
});
273+
})
274+
.catch(err => this.handleError(err))
275+
.catch(() => {
276+
// Ignore if collection not found
277+
return Promise.resolve();
278+
});
264279
}
265280

266281
createClass(className: string, schema: SchemaType): Promise<void> {
@@ -269,13 +284,15 @@ export class MongoStorageAdapter implements StorageAdapter {
269284
mongoObject._id = className;
270285
return this.setIndexesWithSchemaFormat(className, schema.indexes, {}, schema.fields)
271286
.then(() => this._schemaCollection())
272-
.then(schemaCollection => schemaCollection.insertSchema(mongoObject));
287+
.then(schemaCollection => schemaCollection.insertSchema(mongoObject))
288+
.catch(err => this.handleError(err));
273289
}
274290

275291
addFieldIfNotExists(className: string, fieldName: string, type: any): Promise<void> {
276292
return this._schemaCollection()
277293
.then(schemaCollection => schemaCollection.addFieldIfNotExists(className, fieldName, type))
278-
.then(() => this.createIndexesIfNeeded(className, fieldName, type));
294+
.then(() => this.createIndexesIfNeeded(className, fieldName, type))
295+
.catch(err => this.handleError(err));
279296
}
280297

281298
// Drops a collection. Resolves with true if it was a Parse Schema (eg. _User, Custom, etc.)
@@ -293,12 +310,14 @@ export class MongoStorageAdapter implements StorageAdapter {
293310
// We've dropped the collection, now remove the _SCHEMA document
294311
.then(() => this._schemaCollection())
295312
.then(schemaCollection => schemaCollection.findAndDeleteSchema(className))
313+
.catch(err => this.handleError(err));
296314
}
297315

298316
// Delete all data known to this adapter. Used for testing.
299317
deleteAllClasses() {
300318
return storageAdapterAllCollections(this)
301-
.then(collections => Promise.all(collections.map(collection => collection.drop())));
319+
.then(collections => Promise.all(collections.map(collection => collection.drop())))
320+
.catch(err => this.handleError(err));
302321
}
303322

304323
// Remove the column and all the data. For Relations, the _Join collection is handled
@@ -342,14 +361,16 @@ export class MongoStorageAdapter implements StorageAdapter {
342361
return this._adaptiveCollection(className)
343362
.then(collection => collection.updateMany({}, collectionUpdate))
344363
.then(() => this._schemaCollection())
345-
.then(schemaCollection => schemaCollection.updateSchema(className, schemaUpdate));
364+
.then(schemaCollection => schemaCollection.updateSchema(className, schemaUpdate))
365+
.catch(err => this.handleError(err));
346366
}
347367

348368
// Return a promise for all schemas known to this adapter, in Parse format. In case the
349369
// schemas cannot be retrieved, returns a promise that rejects. Requirements for the
350370
// rejection reason are TBD.
351371
getAllClasses(): Promise<StorageClass[]> {
352-
return this._schemaCollection().then(schemasCollection => schemasCollection._fetchAllSchemasFrom_SCHEMA());
372+
return this._schemaCollection().then(schemasCollection => schemasCollection._fetchAllSchemasFrom_SCHEMA())
373+
.catch(err => this.handleError(err));
353374
}
354375

355376
// Return a promise for the schema with the given name, in Parse format. If
@@ -358,6 +379,7 @@ export class MongoStorageAdapter implements StorageAdapter {
358379
getClass(className: string): Promise<StorageClass> {
359380
return this._schemaCollection()
360381
.then(schemasCollection => schemasCollection._fetchOneSchemaFrom_SCHEMA(className))
382+
.catch(err => this.handleError(err));
361383
}
362384

363385
// TODO: As yet not particularly well specified. Creates an object. Maybe shouldn't even need the schema,
@@ -381,7 +403,8 @@ export class MongoStorageAdapter implements StorageAdapter {
381403
throw err;
382404
}
383405
throw error;
384-
});
406+
})
407+
.catch(err => this.handleError(err));
385408
}
386409

387410
// Remove all objects that match the given Parse Query.
@@ -394,6 +417,7 @@ export class MongoStorageAdapter implements StorageAdapter {
394417
const mongoWhere = transformWhere(className, query, schema);
395418
return collection.deleteMany(mongoWhere)
396419
})
420+
.catch(err => this.handleError(err))
397421
.then(({ result }) => {
398422
if (result.n === 0) {
399423
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Object not found.');
@@ -410,7 +434,8 @@ export class MongoStorageAdapter implements StorageAdapter {
410434
const mongoUpdate = transformUpdate(className, update, schema);
411435
const mongoWhere = transformWhere(className, query, schema);
412436
return this._adaptiveCollection(className)
413-
.then(collection => collection.updateMany(mongoWhere, mongoUpdate));
437+
.then(collection => collection.updateMany(mongoWhere, mongoUpdate))
438+
.catch(err => this.handleError(err));
414439
}
415440

416441
// Atomically finds and updates an object based on query.
@@ -427,7 +452,8 @@ export class MongoStorageAdapter implements StorageAdapter {
427452
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'A duplicate value for a field with unique values was provided');
428453
}
429454
throw error;
430-
});
455+
})
456+
.catch(err => this.handleError(err));
431457
}
432458

433459
// Hopefully we can get rid of this. It's only used for config and hooks.
@@ -436,7 +462,8 @@ export class MongoStorageAdapter implements StorageAdapter {
436462
const mongoUpdate = transformUpdate(className, update, schema);
437463
const mongoWhere = transformWhere(className, query, schema);
438464
return this._adaptiveCollection(className)
439-
.then(collection => collection.upsertOne(mongoWhere, mongoUpdate));
465+
.then(collection => collection.upsertOne(mongoWhere, mongoUpdate))
466+
.catch(err => this.handleError(err));
440467
}
441468

442469
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
@@ -461,6 +488,7 @@ export class MongoStorageAdapter implements StorageAdapter {
461488
readPreference,
462489
}))
463490
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)))
491+
.catch(err => this.handleError(err));
464492
}
465493

466494
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
@@ -482,14 +510,15 @@ export class MongoStorageAdapter implements StorageAdapter {
482510
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Tried to ensure field uniqueness for a class that already has duplicates.');
483511
}
484512
throw error;
485-
});
513+
})
514+
.catch(err => this.handleError(err));
486515
}
487516

488517
// Used in tests
489518
_rawFind(className: string, query: QueryType) {
490519
return this._adaptiveCollection(className).then(collection => collection.find(query, {
491520
maxTimeMS: this._maxTimeMS,
492-
}));
521+
})).catch(err => this.handleError(err));
493522
}
494523

495524
// Executes a count.
@@ -500,7 +529,8 @@ export class MongoStorageAdapter implements StorageAdapter {
500529
.then(collection => collection.count(transformWhere(className, query, schema), {
501530
maxTimeMS: this._maxTimeMS,
502531
readPreference,
503-
}));
532+
}))
533+
.catch(err => this.handleError(err));
504534
}
505535

506536
distinct(className: string, schema: SchemaType, query: QueryType, fieldName: string) {
@@ -520,7 +550,8 @@ export class MongoStorageAdapter implements StorageAdapter {
520550
}
521551
return mongoObjectToParseObject(className, object, schema);
522552
});
523-
});
553+
})
554+
.catch(err => this.handleError(err));
524555
}
525556

526557
aggregate(className: string, schema: any, pipeline: any, readPreference: ?string) {
@@ -573,7 +604,8 @@ export class MongoStorageAdapter implements StorageAdapter {
573604
});
574605
return results;
575606
})
576-
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
607+
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)))
608+
.catch(err => this.handleError(err));
577609
}
578610

579611
_parseReadPreference(readPreference: ?string): ?string {
@@ -609,12 +641,14 @@ export class MongoStorageAdapter implements StorageAdapter {
609641

610642
createIndex(className: string, index: any) {
611643
return this._adaptiveCollection(className)
612-
.then(collection => collection._mongoCollection.createIndex(index));
644+
.then(collection => collection._mongoCollection.createIndex(index))
645+
.catch(err => this.handleError(err));
613646
}
614647

615648
createIndexes(className: string, indexes: any) {
616649
return this._adaptiveCollection(className)
617-
.then(collection => collection._mongoCollection.createIndexes(indexes));
650+
.then(collection => collection._mongoCollection.createIndexes(indexes))
651+
.catch(err => this.handleError(err));
618652
}
619653

620654
createIndexesIfNeeded(className: string, fieldName: string, type: any) {
@@ -656,17 +690,20 @@ export class MongoStorageAdapter implements StorageAdapter {
656690

657691
getIndexes(className: string) {
658692
return this._adaptiveCollection(className)
659-
.then(collection => collection._mongoCollection.indexes());
693+
.then(collection => collection._mongoCollection.indexes())
694+
.catch(err => this.handleError(err));
660695
}
661696

662697
dropIndex(className: string, index: any) {
663698
return this._adaptiveCollection(className)
664-
.then(collection => collection._mongoCollection.dropIndex(index));
699+
.then(collection => collection._mongoCollection.dropIndex(index))
700+
.catch(err => this.handleError(err));
665701
}
666702

667703
dropAllIndexes(className: string) {
668704
return this._adaptiveCollection(className)
669-
.then(collection => collection._mongoCollection.dropIndexes());
705+
.then(collection => collection._mongoCollection.dropIndexes())
706+
.catch(err => this.handleError(err));
670707
}
671708

672709
updateSchemaWithIndexes(): Promise<any> {
@@ -676,7 +713,8 @@ export class MongoStorageAdapter implements StorageAdapter {
676713
return this.setIndexesFromMongo(schema.className);
677714
});
678715
return Promise.all(promises);
679-
});
716+
})
717+
.catch(err => this.handleError(err));
680718
}
681719
}
682720

0 commit comments

Comments
 (0)