feat: Remove deprecation DEPPS3: Config option enforcePrivateUsers defaults to true (#8283)

BREAKING CHANGE: The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283)
This commit is contained in:
dblythy
2022-11-17 08:59:44 +11:00
committed by GitHub
parent 6e66b20e28
commit ed499e32a2
12 changed files with 85 additions and 17 deletions

View File

@@ -6,7 +6,7 @@ The following is a list of deprecations, according to the [Deprecation Policy](h
|--------|-------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------| |--------|-------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - | | DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - | | DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - | | DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - | | DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
| DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | | DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
| DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - | | DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |

View File

@@ -292,30 +292,37 @@ describe('ParseGraphQLServer', () => {
let objects = []; let objects = [];
async function prepareData() { async function prepareData() {
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user1 = new Parse.User(); user1 = new Parse.User();
user1.setUsername('user1'); user1.setUsername('user1');
user1.setPassword('user1'); user1.setPassword('user1');
user1.setEmail('user1@user1.user1'); user1.setEmail('user1@user1.user1');
user1.setACL(acl);
await user1.signUp(); await user1.signUp();
user2 = new Parse.User(); user2 = new Parse.User();
user2.setUsername('user2'); user2.setUsername('user2');
user2.setPassword('user2'); user2.setPassword('user2');
user2.setACL(acl);
await user2.signUp(); await user2.signUp();
user3 = new Parse.User(); user3 = new Parse.User();
user3.setUsername('user3'); user3.setUsername('user3');
user3.setPassword('user3'); user3.setPassword('user3');
user3.setACL(acl);
await user3.signUp(); await user3.signUp();
user4 = new Parse.User(); user4 = new Parse.User();
user4.setUsername('user4'); user4.setUsername('user4');
user4.setPassword('user4'); user4.setPassword('user4');
user4.setACL(acl);
await user4.signUp(); await user4.signUp();
user5 = new Parse.User(); user5 = new Parse.User();
user5.setUsername('user5'); user5.setUsername('user5');
user5.setPassword('user5'); user5.setPassword('user5');
user5.setACL(acl);
await user5.signUp(); await user5.signUp();
const roleACL = new Parse.ACL(); const roleACL = new Parse.ACL();
@@ -7066,6 +7073,11 @@ describe('ParseGraphQLServer', () => {
}, },
}, },
}, },
context: {
headers: {
'X-Parse-Master-Key': 'test',
},
},
}); });
expect(result.data.createUser.clientMutationId).toEqual(clientMutationId); expect(result.data.createUser.clientMutationId).toEqual(clientMutationId);
@@ -7123,6 +7135,7 @@ describe('ParseGraphQLServer', () => {
username: 'user2', username: 'user2',
password: 'user2', password: 'user2',
someField: 'someValue2', someField: 'someValue2',
ACL: { public: { read: true, write: true } },
}, },
}, },
someField: 'someValue', someField: 'someValue',
@@ -7195,6 +7208,7 @@ describe('ParseGraphQLServer', () => {
username: 'user2', username: 'user2',
password: 'user2', password: 'user2',
someField: 'someValue2', someField: 'someValue2',
ACL: { public: { read: true, write: true } },
}, },
}, },
}, },
@@ -8308,19 +8322,21 @@ describe('ParseGraphQLServer', () => {
const someClass = new Parse.Object('SomeClass'); const someClass = new Parse.Object('SomeClass');
await someClass.save(); await someClass.save();
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const user = new Parse.User(); const user = new Parse.User();
user.set('username', 'username'); user.set('username', 'username');
user.set('password', 'password'); user.set('password', 'password');
user.setACL(roleACL);
await user.signUp(); await user.signUp();
const user2 = new Parse.User(); const user2 = new Parse.User();
user2.set('username', 'username2'); user2.set('username', 'username2');
user2.set('password', 'password2'); user2.set('password', 'password2');
user2.setACL(roleACL);
await user2.signUp(); await user2.signUp();
const roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
const role = new Parse.Role('aRole', roleACL); const role = new Parse.Role('aRole', roleACL);
await role.save(); await role.save();
@@ -10597,6 +10613,9 @@ describe('ParseGraphQLServer', () => {
const user = new Parse.User(); const user = new Parse.User();
user.setUsername('user1'); user.setUsername('user1');
user.setPassword('user1'); user.setPassword('user1');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.signUp(); await user.signUp();
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear(); await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();

View File

@@ -1076,6 +1076,9 @@ describe('ParseLiveQuery', function () {
user.setUsername('username'); user.setUsername('username');
user.setPassword('password'); user.setPassword('password');
user.set('foo', 'bar'); user.set('foo', 'bar');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
const query = new Parse.Query(Parse.User); const query = new Parse.Query(Parse.User);
query.equalTo('foo', 'bar'); query.equalTo('foo', 'bar');

View File

@@ -6,6 +6,8 @@
const request = require('../lib/request'); const request = require('../lib/request');
function setupTestUsers() { function setupTestUsers() {
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
const user1 = new Parse.User(); const user1 = new Parse.User();
const user2 = new Parse.User(); const user2 = new Parse.User();
const user3 = new Parse.User(); const user3 = new Parse.User();
@@ -18,6 +20,10 @@ function setupTestUsers() {
user2.set('password', 'password'); user2.set('password', 'password');
user3.set('password', 'password'); user3.set('password', 'password');
user1.setACL(acl);
user2.setACL(acl);
user3.setACL(acl);
return user1 return user1
.signUp() .signUp()
.then(() => { .then(() => {

View File

@@ -196,14 +196,13 @@ describe('Parse.User testing', () => {
const ACL = user.getACL(); const ACL = user.getACL();
expect(ACL.getReadAccess(user)).toBe(true); expect(ACL.getReadAccess(user)).toBe(true);
expect(ACL.getWriteAccess(user)).toBe(true); expect(ACL.getWriteAccess(user)).toBe(true);
expect(ACL.getPublicReadAccess()).toBe(true); expect(ACL.getPublicReadAccess()).toBe(false);
expect(ACL.getPublicWriteAccess()).toBe(false); expect(ACL.getPublicWriteAccess()).toBe(false);
const perms = ACL.permissionsById; const perms = ACL.permissionsById;
expect(Object.keys(perms).length).toBe(2); expect(Object.keys(perms).length).toBe(1);
expect(perms[user.id].read).toBe(true); expect(perms[user.id].read).toBe(true);
expect(perms[user.id].write).toBe(true); expect(perms[user.id].write).toBe(true);
expect(perms['*'].read).toBe(true); expect(perms['*']).toBeUndefined();
expect(perms['*'].write).not.toBe(true);
done(); done();
}); });
@@ -875,8 +874,8 @@ describe('Parse.User testing', () => {
kevin.set('password', 'mypass'); kevin.set('password', 'mypass');
await kevin.signUp(); await kevin.signUp();
const query = new Parse.Query(Parse.User); const query = new Parse.Query(Parse.User);
const count = await query.count(); const count = await query.find({ useMasterKey: true });
equal(count, 2); equal(count.length, 2);
done(); done();
}); });
@@ -2153,7 +2152,15 @@ describe('Parse.User testing', () => {
}); });
it("querying for users doesn't get session tokens", done => { it("querying for users doesn't get session tokens", done => {
Parse.User.signUp('finn', 'human', { foo: 'bar' }) const user = new Parse.User();
user.set('username', 'finn');
user.set('password', 'human');
user.set('foo', 'bar');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
user
.signUp()
.then(function () { .then(function () {
return Parse.User.logOut(); return Parse.User.logOut();
}) })
@@ -2162,6 +2169,9 @@ describe('Parse.User testing', () => {
user.set('username', 'jake'); user.set('username', 'jake');
user.set('password', 'dog'); user.set('password', 'dog');
user.set('foo', 'baz'); user.set('foo', 'baz');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
return user.signUp(); return user.signUp();
}) })
.then(function () { .then(function () {
@@ -2188,7 +2198,14 @@ describe('Parse.User testing', () => {
}); });
it('querying for users only gets the expected fields', done => { it('querying for users only gets the expected fields', done => {
Parse.User.signUp('finn', 'human', { foo: 'bar' }).then(() => { const user = new Parse.User();
user.setUsername('finn');
user.setPassword('human');
user.set('foo', 'bar');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
user.signUp().then(() => {
request({ request({
headers: { headers: {
'X-Parse-Application-Id': 'test', 'X-Parse-Application-Id': 'test',
@@ -3426,6 +3443,9 @@ describe('Parse.User testing', () => {
password: 'world', password: 'world',
email: 'test@email.com', email: 'test@email.com',
}); });
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
reconfigureServer({ reconfigureServer({
appName: 'unused', appName: 'unused',
@@ -4057,6 +4077,12 @@ describe('Parse.User testing', () => {
silent: true, silent: true,
}); });
Parse.Cloud.beforeSave(Parse.User, ({ object }) => {
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
object.setACL(acl);
});
const query = new Parse.Query(Parse.User); const query = new Parse.Query(Parse.User);
query.doesNotExist('foo'); query.doesNotExist('foo');
const subscription = await query.subscribe(); const subscription = await query.subscribe();

View File

@@ -13,6 +13,9 @@ describe('ProtectedFields', function () {
user.setPassword('sekrit'); user.setPassword('sekrit');
user.set('email', 'alice@aol.com'); user.set('email', 'alice@aol.com');
user.set('favoriteColor', 'yellow'); user.set('favoriteColor', 'yellow');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save(); await user.save();
const fetched = await new Parse.Query(Parse.User).get(user.id); const fetched = await new Parse.Query(Parse.User).get(user.id);
@@ -35,6 +38,9 @@ describe('ProtectedFields', function () {
user.set('timeZone', 'America/Los_Angeles'); user.set('timeZone', 'America/Los_Angeles');
user.set('favoriteColor', 'yellow'); user.set('favoriteColor', 'yellow');
user.set('favoriteFood', 'pizza'); user.set('favoriteFood', 'pizza');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save(); await user.save();
const fetched = await new Parse.Query(Parse.User).get(user.id); const fetched = await new Parse.Query(Parse.User).get(user.id);
@@ -57,6 +63,9 @@ describe('ProtectedFields', function () {
user.set('timeZone', 'America/Los_Angeles'); user.set('timeZone', 'America/Los_Angeles');
user.set('favoriteColor', 'yellow'); user.set('favoriteColor', 'yellow');
user.set('favoriteFood', 'pizza'); user.set('favoriteFood', 'pizza');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save(); await user.save();
const fetched = await new Parse.Query(Parse.User).get(user.id); const fetched = await new Parse.Query(Parse.User).get(user.id);
@@ -108,6 +117,9 @@ describe('ProtectedFields', function () {
user.set('timeZone', 'America/Los_Angeles'); user.set('timeZone', 'America/Los_Angeles');
user.set('favoriteColor', 'yellow'); user.set('favoriteColor', 'yellow');
user.set('favoriteFood', 'pizza'); user.set('favoriteFood', 'pizza');
const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
user.setACL(acl);
await user.save(); await user.save();
const objA = await new Parse.Object('ClassA').set('foo', 'zzz').set('bar', 'yyy').save(); const objA = await new Parse.Object('ClassA').set('foo', 'zzz').set('bar', 'yyy').save();

View File

@@ -96,6 +96,7 @@ describe('rest query', () => {
let user = { let user = {
username: 'aUsername', username: 'aUsername',
password: 'aPassword', password: 'aPassword',
ACL: { '*': { read: true } },
}; };
const activity = { const activity = {
type: 'comment', type: 'comment',

View File

@@ -16,7 +16,9 @@ describe('Personally Identifiable Information', () => {
await reconfigureServer(); await reconfigureServer();
user = await Parse.User.signUp('tester', 'abc'); user = await Parse.User.signUp('tester', 'abc');
user = await Parse.User.logIn(user.get('username'), 'abc'); user = await Parse.User.logIn(user.get('username'), 'abc');
await user.set('email', EMAIL).set('zip', ZIP).set('ssn', SSN).save(); const acl = new Parse.ACL();
acl.setPublicReadAccess(true);
await user.set('email', EMAIL).set('zip', ZIP).set('ssn', SSN).setACL(acl).save();
done(); done();
}); });

View File

@@ -276,7 +276,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
'Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user' 'Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user'
); );
user user
.fetch() .fetch({ useMasterKey: true })
.then( .then(
() => { () => {
expect(user.get('emailVerified')).toEqual(true); expect(user.get('emailVerified')).toEqual(true);

View File

@@ -16,7 +16,6 @@
* If there are no deprecations, this must return an empty array. * If there are no deprecations, this must return an empty array.
*/ */
module.exports = [ module.exports = [
{ optionKey: 'enforcePrivateUsers', changeNewDefault: 'true' },
{ optionKey: 'allowClientClassCreation', changeNewDefault: 'false' }, { optionKey: 'allowClientClassCreation', changeNewDefault: 'false' },
{ optionKey: 'allowExpiredAuthDataToken', changeNewDefault: 'false' }, { optionKey: 'allowExpiredAuthDataToken', changeNewDefault: 'false' },
]; ];

View File

@@ -217,7 +217,7 @@ module.exports.ParseServerOptions = {
env: 'PARSE_SERVER_ENFORCE_PRIVATE_USERS', env: 'PARSE_SERVER_ENFORCE_PRIVATE_USERS',
help: 'Set to true if new users should be created without public read and write access.', help: 'Set to true if new users should be created without public read and write access.',
action: parsers.booleanParser, action: parsers.booleanParser,
default: false, default: true,
}, },
expireInactiveSessions: { expireInactiveSessions: {
env: 'PARSE_SERVER_EXPIRE_INACTIVE_SESSIONS', env: 'PARSE_SERVER_EXPIRE_INACTIVE_SESSIONS',

View File

@@ -280,7 +280,7 @@ export interface ParseServerOptions {
:DEFAULT: {} */ :DEFAULT: {} */
security: ?SecurityOptions; security: ?SecurityOptions;
/* Set to true if new users should be created without public read and write access. /* Set to true if new users should be created without public read and write access.
:DEFAULT: false */ :DEFAULT: true */
enforcePrivateUsers: ?boolean; enforcePrivateUsers: ?boolean;
/* Allow a user to log in even if the 3rd party authentication token that was used to sign in to their account has expired. If this is set to `false`, then the token will be validated every time the user signs in to their account. This refers to the token that is stored in the `_User.authData` field. Defaults to `true`. /* Allow a user to log in even if the 3rd party authentication token that was used to sign in to their account has expired. If this is set to `false`, then the token will be validated every time the user signs in to their account. This refers to the token that is stored in the `_User.authData` field. Defaults to `true`.
:DEFAULT: true */ :DEFAULT: true */