Added negative scenarios for #5301.

- Public read ACL should never expose PII to authenticated and non-authenticated
    - Explicit ACL like custom user Role should be able to read PII
This commit is contained in:
awgeorge
2019-01-18 10:42:45 +00:00
committed by Arthur Cinader
parent 7a6dc3ff29
commit c69130e0e0

View File

@@ -521,94 +521,216 @@ describe('Personally Identifiable Information', () => {
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
});
describe('with privilaged user', () => { // Explict ACL should be able to read sensitive information
let adminUser; describe('with privilaged user', () => {
let adminUser;
beforeEach(async done => { beforeEach(async done => {
const adminRole = await new Parse.Role( const adminRole = await new Parse.Role(
'Administrator', 'Administrator',
new Parse.ACL() new Parse.ACL()
).save(null, { useMasterKey: true }); ).save(null, { useMasterKey: true });
const managementRole = new Parse.Role( const managementRole = new Parse.Role(
'managementOf_user' + user.id, 'managementOf_user' + user.id,
new Parse.ACL(user) new Parse.ACL(user)
); );
managementRole.getRoles().add(adminRole); managementRole.getRoles().add(adminRole);
await managementRole.save(null, { useMasterKey: true }); await managementRole.save(null, { useMasterKey: true });
const userACL = new Parse.ACL(); const userACL = new Parse.ACL();
userACL.setReadAccess(managementRole, true); userACL.setReadAccess(managementRole, true);
await user.setACL(userACL).save(null, { useMasterKey: true }); await user.setACL(userACL).save(null, { useMasterKey: true });
adminUser = await Parse.User.signUp('administrator', 'secure'); adminUser = await Parse.User.signUp('administrator', 'secure');
adminUser = await Parse.User.logIn(adminUser.get('username'), 'secure'); adminUser = await Parse.User.logIn(adminUser.get('username'), 'secure');
await adminRole await adminRole
.getUsers() .getUsers()
.add(adminUser) .add(adminUser)
.save(null, { useMasterKey: true }); .save(null, { useMasterKey: true });
done(); done();
}); });
it('privilaged user should be able to get user PII via API with object', done => { it('privilaged user should be able to get user PII via API with object', done => {
const userObj = new (Parse.Object.extend(Parse.User))(); const userObj = new (Parse.Object.extend(Parse.User))();
userObj.id = user.id; userObj.id = user.id;
userObj userObj
.fetch() .fetch()
.then( .then(
fetchedUser => { fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL);
},
e => console.error('error', e)
)
.then(done)
.catch(done.fail);
});
it('privilaged user should be able to get user PII via API with Find', done => {
new Parse.Query(Parse.User)
.equalTo('objectId', user.id)
.find()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL); expect(fetchedUser.get('email')).toBe(EMAIL);
}, expect(fetchedUser.get('zip')).toBe(ZIP);
e => console.error('error', e) expect(fetchedUser.get('ssn')).toBe(SSN);
) done();
.then(done) });
.catch(done.fail); });
});
it('privilaged user should be able to get user PII via API with Find', done => { it('privilaged user should be able to get user PII via API with Get', done => {
new Parse.Query(Parse.User) new Parse.Query(Parse.User).get(user.id).then(fetchedUser => {
.equalTo('objectId', user.id)
.find()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(EMAIL); expect(fetchedUser.get('email')).toBe(EMAIL);
expect(fetchedUser.get('zip')).toBe(ZIP); expect(fetchedUser.get('zip')).toBe(ZIP);
expect(fetchedUser.get('ssn')).toBe(SSN); expect(fetchedUser.get('ssn')).toBe(SSN);
done(); done();
}); });
}); });
it('privilaged user should be able to get user PII via API with Get', done => { it('privilaged user should get user PII via REST by ID', done => {
new Parse.Query(Parse.User).get(user.id).then(fetchedUser => { request({
expect(fetchedUser.get('email')).toBe(EMAIL); url: `http://localhost:8378/1/classes/_User/${user.id}`,
expect(fetchedUser.get('zip')).toBe(ZIP); json: true,
expect(fetchedUser.get('ssn')).toBe(SSN); headers: {
done(); 'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
'X-Parse-Session-Token': adminUser.getSessionToken(),
},
})
.then(
response => {
const result = response.data;
const fetchedUser = result;
expect(fetchedUser.zip).toBe(ZIP);
expect(fetchedUser.email).toBe(EMAIL);
},
e => console.error('error', e.message)
)
.then(() => done());
}); });
}); });
it('privilaged user should get user PII via REST by ID', done => { // Public access ACL should always hide sensitive information
request({ describe('with public read ACL', () => {
url: `http://localhost:8378/1/classes/_User/${user.id}`, beforeEach(async done => {
json: true, const userACL = new Parse.ACL();
headers: { userACL.setPublicReadAccess();
'X-Parse-Application-Id': 'test', await user.setACL(userACL).save(null, { useMasterKey: true });
'X-Parse-Javascript-Key': 'test', done();
'X-Parse-Session-Token': adminUser.getSessionToken(), });
},
}) it('should not be able to get user PII via API with object', done => {
.then( Parse.User.logOut().then(() => {
response => { const userObj = new (Parse.Object.extend(Parse.User))();
const result = response.data; userObj.id = user.id;
const fetchedUser = result; userObj
expect(fetchedUser.zip).toBe(ZIP); .fetch()
expect(fetchedUser.email).toBe(EMAIL); .then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
},
e => console.error('error', e)
)
.then(done)
.catch(done.fail);
});
});
it('should not be able to get user PII via API with Find', done => {
Parse.User.logOut().then(() =>
new Parse.Query(Parse.User)
.equalTo('objectId', user.id)
.find()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(undefined);
expect(fetchedUser.get('ssn')).toBe(undefined);
done();
})
);
});
it('should not be able to get user PII via API with Get', done => {
Parse.User.logOut().then(() =>
new Parse.Query(Parse.User).get(user.id).then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(undefined);
expect(fetchedUser.get('ssn')).toBe(undefined);
done();
})
);
});
it('should not get user PII via REST by ID', done => {
request({
url: `http://localhost:8378/1/classes/_User/${user.id}`,
json: true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Javascript-Key': 'test',
}, },
e => console.error('error', e.message) })
) .then(
.then(() => done()); response => {
const result = response.data;
const fetchedUser = result;
expect(fetchedUser.zip).toBe(undefined);
expect(fetchedUser.email).toBe(undefined);
},
e => console.error('error', e.message)
)
.then(() => done());
});
// Even with an authenticated user, Public read ACL should never expose sensitive data.
describe('with another authenticated user', () => {
let anotherUser;
beforeEach(async done => {
return Parse.User.signUp('another', 'abc')
.then(loggedInUser => (anotherUser = loggedInUser))
.then(() => Parse.User.logIn(anotherUser.get('username'), 'abc'))
.then(() => done());
});
it('should not be able to get user PII via API with object', done => {
const userObj = new (Parse.Object.extend(Parse.User))();
userObj.id = user.id;
userObj
.fetch()
.then(
fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
},
e => console.error('error', e)
)
.then(done)
.catch(done.fail);
});
it('should not be able to get user PII via API with Find', done => {
new Parse.Query(Parse.User)
.equalTo('objectId', user.id)
.find()
.then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(undefined);
expect(fetchedUser.get('ssn')).toBe(undefined);
done();
});
});
it('should not be able to get user PII via API with Get', done => {
new Parse.Query(Parse.User).get(user.id).then(fetchedUser => {
expect(fetchedUser.get('email')).toBe(undefined);
expect(fetchedUser.get('zip')).toBe(undefined);
expect(fetchedUser.get('ssn')).toBe(undefined);
done();
});
});
});
}); });
}); });
}); });