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

feat: Pass the set of roles the user has to triggers and cloud functions #9299

Open
wants to merge 7 commits into
base: alpha
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions spec/CloudCode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,56 @@ describe('Cloud Code', () => {
);
});

it('test save triggers get user roles', async () => {
let beforeSaveFlag = false;
let afterSaveFlag = false;
Parse.Cloud.beforeSave('SaveTriggerUserRoles', async req => {
expect(new Set(await req.getUserRoles())).toEqual(new Set(['TestRole1', 'TestRole2']));
beforeSaveFlag = true;
});

Parse.Cloud.afterSave('SaveTriggerUserRoles', async req => {
expect(new Set(await req.getUserRoles())).toEqual(new Set(['TestRole1', 'TestRole2']));
afterSaveFlag = true;
});

const user = new Parse.User();
user.set('password', 'asdf');
user.set('email', '[email protected]');
user.set('username', 'zxcv');
await user.signUp();
const role1 = new Parse.Role('TestRole1', new Parse.ACL({ '*': { read: true, write: true } }));
const role2 = new Parse.Role('TestRole2', new Parse.ACL({ '*': { read: true, write: true } }));
await role1.save();
role2.getRoles().add(role1);
role1.getUsers().add(user);
await Parse.Object.saveAll([role1, role2]);

const obj = new Parse.Object('SaveTriggerUserRoles');
await obj.save();
expect(beforeSaveFlag).toBeTrue();
expect(afterSaveFlag).toBeTrue();
});

it('should not have user roles for anonymous calls', async () => {
let beforeSaveFlag = false;
let afterSaveFlag = false;
Parse.Cloud.beforeSave('SaveTriggerUserRoles', async req => {
expect(req.getUserRoles).toBeUndefined();
beforeSaveFlag = true;
});

Parse.Cloud.afterSave('SaveTriggerUserRoles', async req => {
expect(req.getUserRoles).toBeUndefined();
afterSaveFlag = true;
});

const obj = new Parse.Object('SaveTriggerUserRoles');
await obj.save();
expect(beforeSaveFlag).toBeTrue();
expect(afterSaveFlag).toBeTrue();
});

it('beforeSave change propagates through the save response', done => {
Parse.Cloud.beforeSave('ChangingObject', function (request) {
request.object.set('foo', 'baz');
Expand Down Expand Up @@ -2014,6 +2064,40 @@ describe('cloud functions', () => {

Parse.Cloud.run('myFunction', {}).then(() => done());
});

it('should have user roles', async () => {
let flag = false;
Parse.Cloud.define('myFunction', async req => {
expect(new Set(await req.getUserRoles())).toEqual(new Set(['TestRole1', 'TestRole2']));
flag = true;
});

const user = new Parse.User();
user.set('password', 'asdf');
user.set('email', '[email protected]');
user.set('username', 'zxcv');
await user.signUp();
const role1 = new Parse.Role('TestRole1', new Parse.ACL({ '*': { read: true, write: true } }));
const role2 = new Parse.Role('TestRole2', new Parse.ACL({ '*': { read: true, write: true } }));
await role1.save();
role2.getRoles().add(role1);
role1.getUsers().add(user);
await Parse.Object.saveAll([role1, role2]);

await Parse.Cloud.run('myFunction', { sessionToken: user.getSessionToken() });
expect(flag).toBeTrue();
});

it('should not have user roles for anonymous calls', async () => {
let flag = false;
Parse.Cloud.define('myFunction', async req => {
expect(req.getUserRoles).toBeUndefined();
flag = true;
});

await Parse.Cloud.run('myFunction');
expect(flag).toBeTrue();
});
});

describe('beforeSave hooks', () => {
Expand Down
7 changes: 7 additions & 0 deletions src/Routers/FunctionsRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { promiseEnforceMasterKeyAccess, promiseEnsureIdempotency } from '../midd
import { jobStatusHandler } from '../StatusHandler';
import _ from 'lodash';
import { logger } from '../logger';
import Utils from '../Utils';

function parseObject(obj, config) {
if (Array.isArray(obj)) {
Expand Down Expand Up @@ -131,6 +132,12 @@ export class FunctionsRouter extends PromiseRouter {
params: params,
master: req.auth && req.auth.isMaster,
user: req.auth && req.auth.user,
getUserRoles:
req.auth && req.auth.user
? async () => {
return (await req.auth.getUserRoles()).map(Utils.stripACLRolePrefix);
}
: undefined,
installationId: req.info.installationId,
log: req.config.loggerController,
headers: req.config.headers,
Expand Down
12 changes: 12 additions & 0 deletions src/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,18 @@ class Utils {
}
return obj;
}

/**
* Strips the "role:" prefix from the role name as it appears in the ACL.
*
* @param {String} entry The role name prefixed with the string "role:".
* @returns {String} The role name, without the "role": prefix.
* @example
* stripACLRolePrefix("role:myrole") // Returns "myrole"
*/
static stripACLRolePrefix(entry) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies if my earlier comment wasn't clear. I meant to add a method getUserRoleIds() to where getUserRoles() currently is.

return entry.substr(5 /* 'role:'.length */);
}
}

module.exports = Utils;
4 changes: 4 additions & 0 deletions src/triggers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// triggers.js
import Parse from 'parse/node';
import { logger } from './logger';
import Utils from './Utils';

export const Types = {
beforeLogin: 'beforeLogin',
Expand Down Expand Up @@ -292,6 +293,9 @@ export function getRequestObject(
}
if (auth.user) {
request['user'] = auth.user;
request['getUserRoles'] = async () => {
return (await auth.getUserRoles()).map(Utils.stripACLRolePrefix);
};
}
if (auth.installationId) {
request['installationId'] = auth.installationId;
Expand Down
Loading