Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw error when setting authData to null #6154

Merged
merged 16 commits into from
Oct 28, 2019
Merged
40 changes: 40 additions & 0 deletions spec/MongoTransform.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,46 @@ describe('parseObjectToMongoObjectForCreate', () => {
}).toThrow();
done();
});

it('ignores User authData field in DB so it can be synthesized in code', done => {
const input = {
_id: '123',
_auth_data_acme: { id: 'abc' },
authData: null,
};
const output = transform.mongoObjectToParseObject('_User', input, {
fields: {},
});
expect(output.authData.acme.id).toBe('abc');
done();
});

it('can set authData when not User class', done => {
const input = {
_id: '123',
authData: 'random',
};
const output = transform.mongoObjectToParseObject('TestObject', input, {
fields: {},
});
expect(output.authData).toBe('random');
done();
});
});

it('cannot have a custom field name beginning with underscore', done => {
const input = {
_id: '123',
_thisFieldNameIs: 'invalid',
};
try {
transform.mongoObjectToParseObject('TestObject', input, {
fields: {},
});
} catch (e) {
expect(e).toBeDefined();
}
done();
});

describe('transformUpdate', () => {
Expand Down
10 changes: 10 additions & 0 deletions spec/ParseObject.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,16 @@ describe('Parse.Object testing', () => {
done();
});

it('can set authData when not user class', async () => {
const obj = new Parse.Object('TestObject');
obj.set('authData', 'random');
await obj.save();
expect(obj.get('authData')).toBe('random');
const query = new Parse.Query('TestObject');
const object = await query.get(obj.id, { useMasterKey: true });
expect(object.get('authData')).toBe('random');
});

it('invalid class name', function(done) {
const item = new Parse.Object('Foo^bar');
item.save().then(
Expand Down
51 changes: 51 additions & 0 deletions spec/ParseUser.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,32 @@ describe('Parse.User testing', () => {
done();
});

it('can not set authdata to null', async () => {
try {
const provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
const user = await Parse.User._logInWith('facebook');
user.set('authData', null);
await user.save();
fail();
} catch (e) {
expect(e.message).toBe('This authentication method is unsupported.');
}
});

it('ignore setting authdata to undefined', async () => {
const provider = getMockFacebookProvider();
Parse.User._registerAuthenticationProvider(provider);
const user = await Parse.User._logInWith('facebook');
user.set('authData', undefined);
await user.save();
let authData = user.get('authData');
expect(authData).toBe(undefined);
await user.fetch();
authData = user.get('authData');
expect(authData.facebook.id).toBeDefined();
});

it('user authData should be available in cloudcode (#2342)', async done => {
Parse.Cloud.define('checkLogin', req => {
expect(req.user).not.toBeUndefined();
Expand Down Expand Up @@ -3924,4 +3950,29 @@ describe('Security Advisory GHSA-8w3j-g983-8jh5', function() {
done();
}
);
it_only_db('mongo')('should ignore authData field', async () => {
// Add User to Database with authData
const database = Config.get(Parse.applicationId).database;
const collection = await database.adapter._adaptiveCollection('_User');
await collection.insertOne({
_id: '1234ABCDEF',
name: '<some_name>',
email: '<some_email>',
username: '<some_username>',
_hashed_password: '<some_password>',
_auth_data_custom: {
id: 'linkedID',
},
sessionToken: '<some_session_token>',
authData: null, // should ignore
});
const provider = {
getAuthType: () => 'custom',
restoreAuthentication: () => true,
};
Parse.User._registerAuthenticationProvider(provider);
const query = new Parse.Query(Parse.User);
const user = await query.get('1234ABCDEF', { useMasterKey: true });
expect(user.get('authData')).toEqual({ custom: { id: 'linkedID' } });
});
});
11 changes: 10 additions & 1 deletion src/Adapters/Storage/Mongo/MongoTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -1403,10 +1403,19 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
case 'times_used':
restObject['timesUsed'] = mongoObject[key];
break;
case 'authData':
if (className === '_User') {
log.warn(
mtrezza marked this conversation as resolved.
Show resolved Hide resolved
'ignoring authData in _User as this key is reserved to be synthesized of `_auth_data_*` keys'
);
} else {
restObject['authData'] = mongoObject[key];
}
break;
default:
// Check other auth data keys
var authDataMatch = key.match(/^_auth_data_([a-zA-Z0-9_]+)$/);
if (authDataMatch) {
if (authDataMatch && className === '_User') {
var provider = authDataMatch[1];
restObject['authData'] = restObject['authData'] || {};
restObject['authData'][provider] = mongoObject[key];
Expand Down
15 changes: 14 additions & 1 deletion src/RestWrite.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,21 @@ RestWrite.prototype.validateAuthData = function() {
}
}

if (!this.data.authData || !Object.keys(this.data.authData).length) {
if (
(this.data.authData && !Object.keys(this.data.authData).length) ||
!Object.prototype.hasOwnProperty.call(this.data, 'authData')
) {
// Handle saving authData to {} or if authData doesn't exist
return;
} else if (
Object.prototype.hasOwnProperty.call(this.data, 'authData') &&
!this.data.authData
) {
// Handle saving authData to null
throw new Parse.Error(
Parse.Error.UNSUPPORTED_SERVICE,
'This authentication method is unsupported.'
);
}

var authData = this.data.authData;
Expand Down