diff --git a/spec/vulnerabilities.spec.js b/spec/vulnerabilities.spec.js index 7867e0e0e4..f37e63d4b5 100644 --- a/spec/vulnerabilities.spec.js +++ b/spec/vulnerabilities.spec.js @@ -3294,6 +3294,46 @@ describe('Vulnerabilities', () => { expect(response.data.code).toBe(Parse.Error.OPERATION_FORBIDDEN); }); + it('allows login with authData when public create CLP is disabled', async () => { + const authData = { id: '12345', access_token: '12345' }; + const user = await Parse.User.logInWith('myoauth', { authData }); + await Parse.User.logOut(); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + create: {}, + update: { '*': true }, + delete: { '*': true }, + addField: {}, + }); + + const loggedIn = await Parse.User.logInWith('myoauth', { authData }); + expect(loggedIn.id).toBe(user.id); + expect(loggedIn.getSessionToken()).toBeDefined(); + }); + + it('does not allow signup with authData when public create CLP is disabled', async () => { + const user = new Parse.User(); + user.setUsername('existingUser'); + user.setPassword('password123'); + await user.signUp(); + await Parse.User.logOut(); + + await updateCLP({ + get: { '*': true }, + find: { '*': true }, + create: {}, + update: { '*': true }, + delete: { '*': true }, + addField: {}, + }); + + await expectAsync( + Parse.User.logInWith('myoauth', { authData: { id: '12345', access_token: '12345' } }) + ).toBeRejectedWith(jasmine.objectContaining({ code: Parse.Error.OPERATION_FORBIDDEN })); + }); + it('still returns username taken error when public create CLP is enabled', async () => { const user = new Parse.User(); user.setUsername('existingUser'); diff --git a/src/RestWrite.js b/src/RestWrite.js index ac07596e47..f9426a6961 100644 --- a/src/RestWrite.js +++ b/src/RestWrite.js @@ -824,7 +824,9 @@ RestWrite.prototype.checkRestrictedFields = async function () { // Validates the create or update class-level permission before schema validation RestWrite.prototype.validateWritePermission = async function () { - if (this.auth.isMaster || this.auth.isMaintenance) { + // A login with authData has already matched an existing user and set the response; + // it creates no object, so the create permission does not apply. + if (this.response || this.auth.isMaster || this.auth.isMaintenance) { return; } const schemaController = await this.config.database.loadSchema();