Ensure User ACL's are more flexible and secure #3588 (#4860)

* Fixes an issue that would let the beforeDelete be called when user has no access to the object

* Ensure we properly lock user

- Improves find method so we can attempt to read for a write poking the right ACL instead of using masterKey
- This ensure we do not run beforeDelete/beforeFind/beforeSave in the wrong scenarios

* nits

* Caps insufficient
This commit is contained in:
Florent Vilmart
2018-06-28 16:31:22 -04:00
parent 82fec72ec4
commit 6b36ce1bb5
9 changed files with 158 additions and 39 deletions

View File

@@ -975,6 +975,25 @@ describe('miscellaneous', function() {
});
});
it('test beforeDelete with locked down ACL', async () => {
let called = false;
Parse.Cloud.beforeDelete('GameScore', (req, res) => {
called = true;
res.success();
});
const object = new Parse.Object('GameScore');
object.setACL(new Parse.ACL());
await object.save();
const objects = await new Parse.Query('GameScore').find();
expect(objects.length).toBe(0);
try {
await object.destroy();
} catch(e) {
expect(e.code).toBe(Parse.Error.OBJECT_NOT_FOUND);
}
expect(called).toBe(false);
});
it('test cloud function query parameters', (done) => {
Parse.Cloud.define('echoParams', (req, res) => {
res.success(req.params);

View File

@@ -525,6 +525,71 @@ describe('Parse.User testing', () => {
});
});
it('never locks himself up', async () => {
const user = new Parse.User();
await user.signUp({
username: 'username',
password: 'password'
});
user.setACL(new Parse.ACL());
await user.save();
await user.fetch();
expect(user.getACL().getReadAccess(user)).toBe(true);
expect(user.getACL().getWriteAccess(user)).toBe(true);
const publicReadACL = new Parse.ACL();
publicReadACL.setPublicReadAccess(true);
// Create an administrator role with a single admin user
const role = new Parse.Role('admin', publicReadACL);
const admin = new Parse.User();
await admin.signUp({
username: 'admin',
password: 'admin',
});
role.getUsers().add(admin);
await role.save(null, { useMasterKey: true });
// Grant the admins write rights on the user
const acl = user.getACL();
acl.setRoleWriteAccess(role, true);
acl.setRoleReadAccess(role, true);
// Update with the masterKey just to be sure
await user.save({ ACL: acl }, { useMasterKey: true });
// Try to update from admin... should all work fine
await user.save({ key: 'fromAdmin'}, { sessionToken: admin.getSessionToken() });
await user.fetch();
expect(user.toJSON().key).toEqual('fromAdmin');
// Try to save when logged out (public)
let failed = false;
try {
// Ensure no session token is sent
await Parse.User.logOut();
await user.save({ key: 'fromPublic'});
} catch(e) {
failed = true;
expect(e.code).toBe(Parse.Error.SESSION_MISSING);
}
expect({ failed }).toEqual({ failed: true });
// Try to save with a random user, should fail
failed = false;
const anyUser = new Parse.User();
await anyUser.signUp({
username: 'randomUser',
password: 'password'
});
try {
await user.save({ key: 'fromAnyUser'});
} catch(e) {
failed = true;
expect(e.code).toBe(Parse.Error.SESSION_MISSING);
}
expect({ failed }).toEqual({ failed: true });
});
it("current user", (done) => {
const user = new Parse.User();
user.set("password", "asdf");
@@ -2379,7 +2444,7 @@ describe('Parse.User testing', () => {
}, (error, response, body) => {
expect(error).toBe(null);
const b = JSON.parse(body);
expect(b.error).toBe('invalid session token');
expect(b.error).toBe('Invalid session token');
request.put({
headers: {
'X-Parse-Application-Id': 'test',
@@ -2471,7 +2536,7 @@ describe('Parse.User testing', () => {
expect(error).toBe(null);
const b = JSON.parse(body);
expect(b.code).toEqual(209);
expect(b.error).toBe('invalid session token');
expect(b.error).toBe('Invalid session token');
done();
});
});
@@ -2513,7 +2578,7 @@ describe('Parse.User testing', () => {
}, (error,response,body) => {
const b = JSON.parse(body);
expect(b.code).toEqual(209);
expect(b.error).toBe('invalid session token');
expect(b.error).toBe('Invalid session token');
done();
});
});
@@ -2550,7 +2615,7 @@ describe('Parse.User testing', () => {
done();
}, function(err) {
expect(err.code).toBe(Parse.Error.INVALID_SESSION_TOKEN);
expect(err.message).toBe('invalid session token');
expect(err.message).toBe('Invalid session token');
done();
});
});
@@ -2626,7 +2691,7 @@ describe('Parse.User testing', () => {
});
});
it("invalid session tokens are rejected", (done) => {
it("Invalid session tokens are rejected", (done) => {
Parse.User.signUp("asdf", "zxcv", null, {
success: function() {
request.get({
@@ -2639,7 +2704,7 @@ describe('Parse.User testing', () => {
},
}, (error, response, body) => {
expect(body.code).toBe(209);
expect(body.error).toBe('invalid session token');
expect(body.error).toBe('Invalid session token');
done();
})
}

View File

@@ -114,7 +114,6 @@ if (process.env.PARSE_SERVER_TEST_CACHE === 'redis') {
}
const openConnections = {};
// Set up a default API server for testing with default configuration.
let server;