Skip to content

Commit

Permalink
[backend] Fix missing System and Individual in shared report (#8333)
Browse files Browse the repository at this point in the history
  • Loading branch information
marieflorescontact authored Oct 17, 2024
1 parent dae148d commit f65806d
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 20 deletions.
7 changes: 4 additions & 3 deletions opencti-platform/opencti-graphql/src/manager/taskManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import { isStixCyberObservable } from '../schema/stixCyberObservable';
import { promoteObservableToIndicator } from '../domain/stixCyberObservable';
import { indicatorEditField, promoteIndicatorToObservables } from '../modules/indicator/indicator-domain';
import { askElementEnrichmentForConnector } from '../domain/stixCoreObject';
import { RELATION_GRANTED_TO, RELATION_OBJECT } from '../schema/stixRefRelationship';
import { objectOrganization, RELATION_GRANTED_TO, RELATION_OBJECT } from '../schema/stixRefRelationship';
import {
ACTION_TYPE_COMPLETE_DELETE,
ACTION_TYPE_DELETE,
Expand All @@ -79,6 +79,7 @@ import { BackgroundTaskScope } from '../generated/graphql';
import { ENTITY_TYPE_INTERNAL_FILE } from '../schema/internalObject';
import { deleteFile } from '../database/file-storage';
import { checkUserIsAdminOnDashboard } from '../modules/publicDashboard/publicDashboard-utils';
import { ENTITY_TYPE_IDENTITY_ORGANIZATION } from '../modules/organization/organization-types';

// Task manager responsible to execute long manual tasks
// Each API will start is task manager.
Expand Down Expand Up @@ -406,7 +407,7 @@ const executeShare = async (context, user, actionContext, element) => {
for (let indexCreate = 0; indexCreate < values.length; indexCreate += 1) {
const target = values[indexCreate];
const currentGrants = element[buildRefRelationKey(RELATION_GRANTED_TO)] ?? [];
if (!currentGrants.includes(target)) {
if (!currentGrants.includes(target) && objectOrganization.isRefExistingForTypes(element.entity_type, ENTITY_TYPE_IDENTITY_ORGANIZATION)) {
await createRelation(context, user, { fromId: element.id, toId: target, relationship_type: RELATION_GRANTED_TO });
}
}
Expand Down Expand Up @@ -549,7 +550,7 @@ const executeProcessing = async (context, user, job, scope) => {
return errors;
};

const taskHandler = async () => {
export const taskHandler = async () => {
let lock;
try {
// Lock the manager
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
ENTITY_TYPE_IDENTITY_SYSTEM,
ENTITY_TYPE_LOCATION_COUNTRY,
isStixDomainObjectContainer,
isStixDomainObjectIdentity,
isStixDomainObjectLocation
} from './stixDomainObject';
import { ENTITY_TYPE_EXTERNAL_REFERENCE, ENTITY_TYPE_KILL_CHAIN_PHASE, ENTITY_TYPE_LABEL, ENTITY_TYPE_MARKING_DEFINITION } from './stixMetaObject';
Expand Down Expand Up @@ -727,7 +726,9 @@ export const objectOrganization: RefAttribute = {
multiple: true,
upsert: true,
isRefExistingForTypes(this, fromType, toType) {
return !(fromType === ENTITY_TYPE_EVENT || isStixDomainObjectIdentity(fromType)
return !(fromType === ENTITY_TYPE_EVENT
|| fromType === ENTITY_TYPE_IDENTITY_ORGANIZATION
|| fromType === ENTITY_TYPE_IDENTITY_SECTOR
|| isStixDomainObjectLocation(fromType))
&& this.toTypes.includes(toType);
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { describe, expect, it } from 'vitest';
import gql from 'graphql-tag';
import {
ADMIN_API_TOKEN,
ADMIN_USER,
API_URI,
FIVE_MINUTES,
getOrganizationIdByName,
PLATFORM_ORGANIZATION,
PYTHON_PATH,
TEST_ORGANIZATION,
testContext,
USER_EDITOR
} from '../../utils/testQuery';
import { adminQueryWithSuccess, enableCEAndUnSetOrganization, enableEEAndSetOrganization, queryAsUserWithSuccess } from '../../utils/testQueryHelper';
import { findById } from '../../../src/domain/report';
import { execChildPython } from '../../../src/python/pythonBridge';
import { taskHandler } from '../../../src/manager/taskManager';

const ORGANIZATION_SHARING_QUERY = gql`
mutation StixCoreObjectSharingGroupAddMutation(
$id: ID!
$organizationId: ID!
) {
stixCoreObjectEdit(id: $id) {
restrictionOrganizationAdd(organizationId: $organizationId) {
id
objectOrganization {
id
name
}
}
}
}
`;

const REPORT_STIX_DOMAIN_ENTITIES = gql`
query report($id: String!) {
report(id: $id) {
id
standard_id
objects(first: 30) {
edges {
node {
... on BasicObject {
id
standard_id
}
... on BasicRelationship {
id
standard_id
}
}
}
}
}
}
`;

const importOpts: string[] = [API_URI, ADMIN_API_TOKEN, './tests/data/organization-sharing/20241003_Report_to_test_orga_sharing_full.json'];

describe('Database provision', () => {
it('Should import creation succeed', async () => {
// Inject data
const execution = await execChildPython(testContext, ADMIN_USER, PYTHON_PATH, 'local_importer.py', importOpts);
expect(execution).not.toBeNull();
expect(execution.status).toEqual('success');
}, FIVE_MINUTES);
// Python lib is fixed but we need to wait for a new release
it('Should import update succeed', async () => {
const execution = await execChildPython(testContext, ADMIN_USER, PYTHON_PATH, 'local_importer.py', importOpts);
expect(execution).not.toBeNull();
expect(execution.status).toEqual('success');
}, FIVE_MINUTES);
});

describe('Organization sharing standard behavior for container', () => {
let reportInternalId: string;
let organizationId: string;
it('should load Report', async () => {
const report = await findById(testContext, ADMIN_USER, 'report--ce32448d-733b-5e34-ac4f-2759ce5db1ae');
expect(report).not.toBeUndefined();
reportInternalId = report.id;
});
it('should platform organization sharing and EE activated', async () => {
await enableEEAndSetOrganization(PLATFORM_ORGANIZATION);
});
it('should user from different organization not access the report', async () => {
const queryResult = await queryAsUserWithSuccess(USER_EDITOR.client, {
query: REPORT_STIX_DOMAIN_ENTITIES,
variables: { id: reportInternalId },
});
expect(queryResult.data.report).toBeNull();
});
it('should share Report with Organization', async () => {
// Get organization id
organizationId = await getOrganizationIdByName(TEST_ORGANIZATION.name);
const organizationSharingQueryResult = await adminQueryWithSuccess({
query: ORGANIZATION_SHARING_QUERY,
variables: { id: reportInternalId, organizationId }
});
expect(organizationSharingQueryResult?.data?.stixCoreObjectEdit.restrictionOrganizationAdd).not.toBeNull();
expect(organizationSharingQueryResult?.data?.stixCoreObjectEdit.restrictionOrganizationAdd.objectOrganization[0].name).toEqual(TEST_ORGANIZATION.name);

// Need background task magic to happens for sharing
await taskHandler();
});
it('should Editor user access all objects', async () => {
const queryResult = await queryAsUserWithSuccess(USER_EDITOR.client, {
query: REPORT_STIX_DOMAIN_ENTITIES,
variables: { id: reportInternalId },
});
expect(queryResult.data.report.objects.edges.length).toEqual(8);
});
it('should all entities deleted', async () => {
const PURGE_QUERY = gql`
mutation ReportPopoverDeletionMutation(
$id: ID!
$purgeElements: Boolean
) {
reportEdit(id: $id) {
delete(purgeElements: $purgeElements)
}
}
`;
const purgeQueryResult = await adminQueryWithSuccess({
query: PURGE_QUERY,
variables: {
id: reportInternalId,
purgeElements: true
}
});
expect(purgeQueryResult.data.reportEdit.delete).toEqual(reportInternalId);
});
it('should plateform organization sharing and EE deactivated', async () => {
await enableCEAndUnSetOrganization();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ describe('Raw streams tests', () => {
expect(createEventsByTypes['kill-chain-phase'].length).toBe(3);
expect(createEventsByTypes['course-of-action'].length).toBe(3);
expect(createEventsByTypes.label.length).toBe(15);
expect(createEventsByTypes.identity.length).toBe(32);
expect(createEventsByTypes.location.length).toBe(15);
expect(createEventsByTypes.identity.length).toBe(36);
expect(createEventsByTypes.location.length).toBe(16);
expect(createEventsByTypes.relationship.length).toBe(136);
expect(createEventsByTypes.sighting.length).toBe(4);
expect(createEventsByTypes.indicator.length).toBe(36);
expect(createEventsByTypes.indicator.length).toBe(37);
expect(createEventsByTypes['attack-pattern'].length).toBe(9);
expect(createEventsByTypes['threat-actor'].length).toBe(13);
expect(createEventsByTypes['observed-data'].length).toBe(1);
Expand All @@ -37,16 +37,16 @@ describe('Raw streams tests', () => {
expect(createEventsByTypes['ipv4-addr'].length).toBe(1);
expect(createEventsByTypes['data-component'].length).toBe(5);
expect(createEventsByTypes['data-source'].length).toBe(1);
expect(createEventsByTypes.malware.length).toBe(44);
expect(createEventsByTypes.malware.length).toBe(45);
expect(createEventsByTypes.software.length).toBe(1);
expect(createEventsByTypes.file.length).toBe(4);
expect(createEventsByTypes.campaign.length).toBe(5);
expect(createEventsByTypes.incident.length).toBe(2);
expect(createEventsByTypes.report.length).toBe(35);
expect(createEventsByTypes.report.length).toBe(36);
expect(createEventsByTypes.tool.length).toBe(2);
expect(createEventsByTypes.vocabulary.length).toBe(342); // 328 created at init + 2 created in tests + 5 vocabulary organizations types + 7 persona
expect(createEventsByTypes.vulnerability.length).toBe(7);
expect(createEvents.length).toBe(784);
expect(createEvents.length).toBe(793);
for (let createIndex = 0; createIndex < createEvents.length; createIndex += 1) {
const { data: insideData, origin, type } = createEvents[createIndex];
expect(origin).toBeDefined();
Expand All @@ -58,8 +58,8 @@ describe('Raw streams tests', () => {
expect(updateEventsByTypes['marking-definition'].length).toBe(2);
expect(updateEventsByTypes['campaign'].length).toBe(7);
expect(updateEventsByTypes['relationship'].length).toBe(8);
expect(updateEventsByTypes['identity'].length).toBe(16);
expect(updateEventsByTypes['malware'].length).toBe(16);
expect(updateEventsByTypes['identity'].length).toBe(18);
expect(updateEventsByTypes['malware'].length).toBe(17);
expect(updateEventsByTypes['intrusion-set'].length).toBe(4);
expect(updateEventsByTypes['data-component'].length).toBe(4);
expect(updateEventsByTypes['location'].length).toBe(14);
Expand All @@ -70,19 +70,19 @@ describe('Raw streams tests', () => {
expect(updateEventsByTypes['external-reference'].length).toBe(1);
expect(updateEventsByTypes['grouping'].length).toBe(3);
expect(updateEventsByTypes['incident'].length).toBe(3);
expect(updateEventsByTypes['indicator'].length).toBe(4);
expect(updateEventsByTypes['indicator'].length).toBe(5);
expect(updateEventsByTypes['label'].length).toBe(1);
expect(updateEventsByTypes['malware-analysis'].length).toBe(3);
expect(updateEventsByTypes['note'].length).toBe(3);
expect(updateEventsByTypes['opinion'].length).toBe(6);
expect(updateEventsByTypes['report'].length).toBe(12);
expect(updateEventsByTypes['report'].length).toBe(13);
expect(updateEventsByTypes['ipv4-addr'].length).toBe(3);
expect(updateEventsByTypes['tool'].length).toBe(7);
expect(updateEventsByTypes['sighting'].length).toBe(4);
expect(updateEventsByTypes['threat-actor'].length).toBe(17);
expect(updateEventsByTypes['vocabulary'].length).toBe(3);
expect(updateEventsByTypes['vulnerability'].length).toBe(3);
expect(updateEvents.length).toBe(163);
expect(updateEvents.length).toBe(169);
for (let updateIndex = 0; updateIndex < updateEvents.length; updateIndex += 1) {
const event = updateEvents[updateIndex];
const { data: insideData, origin, type } = event;
Expand All @@ -95,7 +95,7 @@ describe('Raw streams tests', () => {
}
// 03 - CHECK DELETE EVENTS
const deleteEvents = events.filter((e) => e.type === EVENT_TYPE_DELETE);
expect(deleteEvents.length).toBe(135);
expect(deleteEvents.length).toBe(144);
// const deleteEventsByTypes = R.groupBy((e) => e.data.data.type, deleteEvents);
for (let delIndex = 0; delIndex < deleteEvents.length; delIndex += 1) {
const { data: insideData, origin, type } = deleteEvents[delIndex];
Expand Down
Loading

0 comments on commit f65806d

Please sign in to comment.