fix(core): Fix broken API permissions in public API (#5978)

This commit is contained in:
Omar Ajoue 2023-04-14 11:05:42 +02:00 committed by GitHub
parent 536d8109b0
commit 49d838f628
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 142 additions and 6 deletions

View file

@ -91,7 +91,7 @@ export = {
// user does not have workflows hence no executions // user does not have workflows hence no executions
// or the execution he is trying to access belongs to a workflow he does not own // or the execution he is trying to access belongs to a workflow he does not own
if (!sharedWorkflowsIds.length) { if (!sharedWorkflowsIds.length || (workflowId && !sharedWorkflowsIds.includes(workflowId))) {
return res.status(200).json({ data: [], nextCursor: null }); return res.status(200).json({ data: [], nextCursor: null });
} }
@ -105,7 +105,7 @@ export = {
limit, limit,
lastId, lastId,
includeData, includeData,
...(workflowId && { workflowIds: [workflowId] }), workflowIds: workflowId ? [workflowId] : sharedWorkflowsIds,
excludedExecutionsIds: runningExecutionsIds, excludedExecutionsIds: runningExecutionsIds,
}; };

View file

@ -18,9 +18,12 @@ function insertIf(condition: boolean, elements: string[]): string[] {
} }
export async function getSharedWorkflowIds(user: User): Promise<string[]> { export async function getSharedWorkflowIds(user: User): Promise<string[]> {
const where = user.globalRole.name === 'owner' ? {} : { userId: user.id };
const sharedWorkflows = await Db.collections.SharedWorkflow.find({ const sharedWorkflows = await Db.collections.SharedWorkflow.find({
where: { userId: user.id }, where,
select: ['workflowId'],
}); });
return sharedWorkflows.map(({ workflowId }) => workflowId);
return sharedWorkflows.map(({ workflowId }) => workflowId); return sharedWorkflows.map(({ workflowId }) => workflowId);
} }

View file

@ -10,7 +10,11 @@ import * as testDb from '../shared/testDb';
let app: Application; let app: Application;
let owner: User; let owner: User;
let user1: User;
let user2: User;
let authOwnerAgent: SuperAgentTest; let authOwnerAgent: SuperAgentTest;
let authUser1Agent: SuperAgentTest;
let authUser2Agent: SuperAgentTest;
let workflowRunner: ActiveWorkflowRunner; let workflowRunner: ActiveWorkflowRunner;
beforeAll(async () => { beforeAll(async () => {
@ -21,7 +25,10 @@ beforeAll(async () => {
}); });
const globalOwnerRole = await testDb.getGlobalOwnerRole(); const globalOwnerRole = await testDb.getGlobalOwnerRole();
const globalUserRole = await testDb.getGlobalMemberRole();
owner = await testDb.createUser({ globalRole: globalOwnerRole, apiKey: randomApiKey() }); owner = await testDb.createUser({ globalRole: globalOwnerRole, apiKey: randomApiKey() });
user1 = await testDb.createUser({ globalRole: globalUserRole, apiKey: randomApiKey() });
user2 = await testDb.createUser({ globalRole: globalUserRole, apiKey: randomApiKey() });
await utils.initBinaryManager(); await utils.initBinaryManager();
await utils.initNodeTypes(); await utils.initNodeTypes();
@ -46,6 +53,20 @@ beforeEach(async () => {
version: 1, version: 1,
}); });
authUser1Agent = utils.createAgent(app, {
apiPath: 'public',
auth: true,
user: user1,
version: 1,
});
authUser2Agent = utils.createAgent(app, {
apiPath: 'public',
auth: true,
user: user2,
version: 1,
});
config.set('userManagement.disabled', false); config.set('userManagement.disabled', false);
config.set('userManagement.isInstanceOwnerSetUp', true); config.set('userManagement.isInstanceOwnerSetUp', true);
}); });
@ -70,7 +91,7 @@ describe('GET /executions/:id', () => {
test('should fail due to invalid API Key', testWithAPIKey('get', '/executions/1', 'abcXYZ')); test('should fail due to invalid API Key', testWithAPIKey('get', '/executions/1', 'abcXYZ'));
test('should get an execution', async () => { test('owner should be able to get an execution owned by him', async () => {
const workflow = await testDb.createWorkflow({}, owner); const workflow = await testDb.createWorkflow({}, owner);
const execution = await testDb.createSuccessfulExecution(workflow); const execution = await testDb.createSuccessfulExecution(workflow);
@ -101,6 +122,46 @@ describe('GET /executions/:id', () => {
expect(workflowId).toBe(execution.workflowId); expect(workflowId).toBe(execution.workflowId);
expect(waitTill).toBeNull(); expect(waitTill).toBeNull();
}); });
test('owner should be able to read executions of other users', async () => {
const workflow = await testDb.createWorkflow({}, user1);
const execution = await testDb.createSuccessfulExecution(workflow);
const response = await authOwnerAgent.get(`/executions/${execution.id}`);
expect(response.statusCode).toBe(200);
});
test('member should be able to fetch his own executions', async () => {
const workflow = await testDb.createWorkflow({}, user1);
const execution = await testDb.createSuccessfulExecution(workflow);
const response = await authUser1Agent.get(`/executions/${execution.id}`);
expect(response.statusCode).toBe(200);
});
test('member should not get an execution of another user without the workflow being shared', async () => {
const workflow = await testDb.createWorkflow({}, owner);
const execution = await testDb.createSuccessfulExecution(workflow);
const response = await authUser1Agent.get(`/executions/${execution.id}`);
expect(response.statusCode).toBe(404);
});
test('member should be able to fetch executions of workflows shared with him', async () => {
const workflow = await testDb.createWorkflow({}, user1);
const execution = await testDb.createSuccessfulExecution(workflow);
await testDb.shareWorkflowWithUsers(workflow, [user2]);
const response = await authUser2Agent.get(`/executions/${execution.id}`);
expect(response.statusCode).toBe(200);
});
}); });
describe('DELETE /executions/:id', () => { describe('DELETE /executions/:id', () => {
@ -324,10 +385,8 @@ describe('GET /executions', () => {
const savedExecutions = await testDb.createManyExecutions( const savedExecutions = await testDb.createManyExecutions(
2, 2,
workflow, workflow,
// @ts-ignore
testDb.createSuccessfulExecution, testDb.createSuccessfulExecution,
); );
// @ts-ignore
await testDb.createManyExecutions(2, workflow2, testDb.createSuccessfulExecution); await testDb.createManyExecutions(2, workflow2, testDb.createSuccessfulExecution);
const response = await authOwnerAgent.get(`/executions`).query({ const response = await authOwnerAgent.get(`/executions`).query({
@ -362,4 +421,78 @@ describe('GET /executions', () => {
expect(waitTill).toBeNull(); expect(waitTill).toBeNull();
} }
}); });
test('owner should retrieve all executions regardless of ownership', async () => {
const [firstWorkflowForUser1, secondWorkflowForUser1] = await testDb.createManyWorkflows(
2,
{},
user1,
);
await testDb.createManyExecutions(2, firstWorkflowForUser1, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser1, testDb.createSuccessfulExecution);
const [firstWorkflowForUser2, secondWorkflowForUser2] = await testDb.createManyWorkflows(
2,
{},
user2,
);
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
const response = await authOwnerAgent.get(`/executions`);
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(8);
expect(response.body.nextCursor).toBe(null);
});
test('member should not see executions of workflows not shared with him', async () => {
const [firstWorkflowForUser1, secondWorkflowForUser1] = await testDb.createManyWorkflows(
2,
{},
user1,
);
await testDb.createManyExecutions(2, firstWorkflowForUser1, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser1, testDb.createSuccessfulExecution);
const [firstWorkflowForUser2, secondWorkflowForUser2] = await testDb.createManyWorkflows(
2,
{},
user2,
);
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
const response = await authUser1Agent.get(`/executions`);
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(4);
expect(response.body.nextCursor).toBe(null);
});
test('member should also see executions of workflows shared with him', async () => {
const [firstWorkflowForUser1, secondWorkflowForUser1] = await testDb.createManyWorkflows(
2,
{},
user1,
);
await testDb.createManyExecutions(2, firstWorkflowForUser1, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser1, testDb.createSuccessfulExecution);
const [firstWorkflowForUser2, secondWorkflowForUser2] = await testDb.createManyWorkflows(
2,
{},
user2,
);
await testDb.createManyExecutions(2, firstWorkflowForUser2, testDb.createSuccessfulExecution);
await testDb.createManyExecutions(2, secondWorkflowForUser2, testDb.createSuccessfulExecution);
await testDb.shareWorkflowWithUsers(firstWorkflowForUser2, [user1]);
const response = await authUser1Agent.get(`/executions`);
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(6);
expect(response.body.nextCursor).toBe(null);
});
}); });