diff --git a/opencti-platform/opencti-front/src/private/components/data/playbooks/PlaybookAddComponents.jsx b/opencti-platform/opencti-front/src/private/components/data/playbooks/PlaybookAddComponents.jsx
index 2a5e8484155e..861355986a76 100644
--- a/opencti-platform/opencti-front/src/private/components/data/playbooks/PlaybookAddComponents.jsx
+++ b/opencti-platform/opencti-front/src/private/components/data/playbooks/PlaybookAddComponents.jsx
@@ -20,6 +20,7 @@ import Box from '@mui/material/Box';
import Alert from '@mui/material/Alert';
import Drawer from '../../common/drawer/Drawer';
import ObjectMembersField from '../../common/form/ObjectMembersField';
+import ObjectOrganizationField from '../../common/form/ObjectOrganizationField';
import CreatedByField from '../../common/form/CreatedByField';
import Filters from '../../common/lists/Filters';
import FilterIconButton from '../../../../components/FilterIconButton';
@@ -458,6 +459,18 @@ const PlaybookAddComponentsContent = ({
/>
);
}
+ if (k === 'organizations') {
+ return (
+
+ );
+ }
if (k === 'filters') {
return (
diff --git a/opencti-platform/opencti-graphql/src/modules/playbook/playbook-components.ts b/opencti-platform/opencti-graphql/src/modules/playbook/playbook-components.ts
index 913e644ff8e9..0c50e9cf15d7 100644
--- a/opencti-platform/opencti-graphql/src/modules/playbook/playbook-components.ts
+++ b/opencti-platform/opencti-graphql/src/modules/playbook/playbook-components.ts
@@ -49,21 +49,14 @@ import {
import type { CyberObjectExtension, StixBundle, StixCoreObject, StixCyberObject, StixDomainObject, StixObject, StixOpenctiExtension } from '../../types/stix-common';
import { STIX_EXT_OCTI, STIX_EXT_OCTI_SCO } from '../../types/stix-extensions';
import { connectorsForPlaybook } from '../../database/repository';
-import { listAllEntities, listAllRelations, storeLoadById } from '../../database/middleware-loader';
-import type { BasicStoreEntityOrganization } from '../organization/organization-types';
+import { internalFindByIds, listAllRelations, storeLoadById } from '../../database/middleware-loader';
import { ENTITY_TYPE_IDENTITY_ORGANIZATION } from '../organization/organization-types';
import { getEntitiesListFromCache, getEntitiesMapFromCache } from '../../database/cache';
import { createdBy, objectLabel, objectMarking } from '../../schema/stixRefRelationship';
import { logApp } from '../../config/conf';
import { FunctionalError } from '../../config/errors';
import { extractStixRepresentative } from '../../database/stix-representative';
-import {
- isEmptyField,
- isNotEmptyField,
- READ_ENTITIES_INDICES_WITHOUT_INFERRED,
- READ_RELATIONSHIPS_INDICES,
- READ_RELATIONSHIPS_INDICES_WITHOUT_INFERRED
-} from '../../database/utils';
+import { isEmptyField, isNotEmptyField, READ_RELATIONSHIPS_INDICES, READ_RELATIONSHIPS_INDICES_WITHOUT_INFERRED } from '../../database/utils';
import { schemaAttributesDefinition } from '../../schema/schema-attributes';
import { schemaRelationsRefDefinition } from '../../schema/schema-relationsRef';
import { stixLoadByIds } from '../../database/middleware';
@@ -496,8 +489,8 @@ const PLAYBOOK_CONTAINER_WRAPPER_COMPONENT: PlaybookComponent = {
type: 'object',
@@ -521,25 +514,20 @@ const PLAYBOOK_SHARING_COMPONENT: PlaybookComponent = {
is_internal: true,
ports: [{ id: 'out', type: 'out' }],
configuration_schema: PLAYBOOK_SHARING_COMPONENT_SCHEMA,
- schema: async () => {
- const context = executionContext('playbook_components');
- const organizations = await listAllEntities(
- context,
- SYSTEM_USER,
- [ENTITY_TYPE_IDENTITY_ORGANIZATION],
- { connectionFormat: false, indices: READ_ENTITIES_INDICES_WITHOUT_INFERRED }
- );
- const elements = organizations.map((c) => ({ const: c.id, title: c.name }));
- const schemaElement = { properties: { organizations: { items: { oneOf: elements } } } };
- return R.mergeDeepRight, any>(PLAYBOOK_SHARING_COMPONENT_SCHEMA, schemaElement);
- },
+ schema: async () => PLAYBOOK_SHARING_COMPONENT_SCHEMA,
executor: async ({ dataInstanceId, playbookNode, bundle }) => {
const context = executionContext('playbook_components');
- const allOrganizations = await getEntitiesListFromCache(context, SYSTEM_USER, ENTITY_TYPE_IDENTITY_ORGANIZATION);
const { organizations } = playbookNode.configuration;
- const organizationIds = allOrganizations
- .filter((o) => (organizations ?? []).includes(o.internal_id))
- .map((o) => o.standard_id);
+ const organizationsValues = organizations.map((o) => (typeof o !== 'string' ? o.value : o));
+ const organizationsByIds = await internalFindByIds(context, SYSTEM_USER, organizationsValues, {
+ type: ENTITY_TYPE_IDENTITY_ORGANIZATION,
+ baseData: true,
+ baseFields: ['standard_id']
+ });
+ if (organizationsByIds.length === 0) {
+ return { output_port: 'out', bundle }; // nothing to do since organizations are empty
+ }
+ const organizationIds = organizationsByIds.map((o) => o.standard_id);
const baseData = bundle.objects.find((o) => o.id === dataInstanceId) as StixCoreObject;
baseData.extensions[STIX_EXT_OCTI].granted_refs = [...(baseData.extensions[STIX_EXT_OCTI].granted_refs ?? []), ...organizationIds];
return { output_port: 'out', bundle };
diff --git a/opencti-platform/opencti-graphql/src/modules/playbook/playbook-domain.ts b/opencti-platform/opencti-graphql/src/modules/playbook/playbook-domain.ts
index fd3e98cba864..4be5a38e3098 100644
--- a/opencti-platform/opencti-graphql/src/modules/playbook/playbook-domain.ts
+++ b/opencti-platform/opencti-graphql/src/modules/playbook/playbook-domain.ts
@@ -16,7 +16,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
import { v4 as uuidv4 } from 'uuid';
import { BUS_TOPICS, logApp } from '../../config/conf';
import { createEntity, deleteElementById, patchAttribute, updateAttribute } from '../../database/middleware';
-import { type EntityOptions, listAllEntities, listEntitiesPaginated, storeLoadById } from '../../database/middleware-loader';
+import { type EntityOptions, internalFindByIds, listAllEntities, listEntitiesPaginated, storeLoadById } from '../../database/middleware-loader';
import { notify } from '../../database/redis';
import type { DomainFindById } from '../../domain/domainTypes';
import { ABSTRACT_INTERNAL_OBJECT } from '../../schema/general';
@@ -24,8 +24,10 @@ import type { AuthContext, AuthUser } from '../../types/user';
import type { EditInput, FilterGroup, PlaybookAddInput, PlaybookAddLinkInput, PlaybookAddNodeInput, PositionInput } from '../../generated/graphql';
import type { BasicStoreEntityPlaybook, ComponentDefinition, LinkDefinition, NodeDefinition } from './playbook-types';
import { ENTITY_TYPE_PLAYBOOK } from './playbook-types';
-import { PLAYBOOK_COMPONENTS } from './playbook-components';
+import { PLAYBOOK_COMPONENTS, type SharingConfiguration } from './playbook-components';
import { UnsupportedError } from '../../config/errors';
+import { type BasicStoreEntityOrganization, ENTITY_TYPE_IDENTITY_ORGANIZATION } from '../organization/organization-types';
+import { SYSTEM_USER } from '../../utils/access';
import { validateFilterGroupForStixMatch } from '../../utils/filtering/filtering-stix/stix-filtering';
import { registerConnectorQueues, unregisterConnector } from '../../database/rabbitmq';
@@ -45,6 +47,38 @@ export const availableComponents = () => {
return Object.values(PLAYBOOK_COMPONENTS);
};
+export const getPlaybookDefinition = async (context: AuthContext, playbook: BasicStoreEntityPlaybook) => {
+ if (playbook.playbook_definition && playbook.playbook_definition.includes('PLAYBOOK_SHARING_COMPONENT')) {
+ // parse playbook definition in case there is a sharing with organization component, in order to parse organizations to get their label
+ const definition = JSON.parse(playbook.playbook_definition) as ComponentDefinition;
+ const sharingComponent = definition.nodes.find((n) => n.component_id === 'PLAYBOOK_SHARING_COMPONENT');
+ if (sharingComponent && sharingComponent.configuration) {
+ const sharingConfiguration = JSON.parse(sharingComponent.configuration) as SharingConfiguration;
+ const organizationsIds = sharingConfiguration.organizations.filter((o) => typeof o === 'string');
+ if (organizationsIds.length === 0) {
+ return playbook.playbook_definition; // nothing to map, already mapped
+ }
+ const organizationsByIds = await internalFindByIds(context, SYSTEM_USER, organizationsIds, {
+ type: ENTITY_TYPE_IDENTITY_ORGANIZATION,
+ baseData: true,
+ baseFields: ['internal_id', 'name'],
+ toMap: true,
+ }) as unknown as { [k: string]: BasicStoreEntityOrganization };
+ const organizationsWithNames = [];
+ for (let i = 0; i < organizationsIds.length; i += 1) {
+ const orgId = organizationsIds[i];
+ if (organizationsByIds[orgId]) {
+ organizationsWithNames.push({ label: organizationsByIds[orgId].name, value: orgId });
+ }
+ }
+ sharingConfiguration.organizations = organizationsWithNames;
+ sharingComponent.configuration = JSON.stringify(sharingConfiguration);
+ return JSON.stringify(definition);
+ }
+ }
+ return playbook.playbook_definition;
+};
+
export const playbookAddNode = async (context: AuthContext, user: AuthUser, id: string, input: PlaybookAddNodeInput) => {
// our stix matching is currently limited, we need to validate the input filters
if (input.configuration) {
diff --git a/opencti-platform/opencti-graphql/src/modules/playbook/playbook-resolvers.ts b/opencti-platform/opencti-graphql/src/modules/playbook/playbook-resolvers.ts
index 25aec50c0eb1..06fecadcb6ea 100644
--- a/opencti-platform/opencti-graphql/src/modules/playbook/playbook-resolvers.ts
+++ b/opencti-platform/opencti-graphql/src/modules/playbook/playbook-resolvers.ts
@@ -28,6 +28,7 @@ import {
playbookDeleteNode,
playbookDeleteLink,
playbookUpdatePositions,
+ getPlaybookDefinition
} from './playbook-domain';
import { playbookStepExecution } from '../../manager/playbookManager';
import { getLastPlaybookExecutions } from '../../database/redis';
@@ -42,6 +43,7 @@ const playbookResolvers: Resolvers = {
playbookComponents: () => availableComponents(),
},
Playbook: {
+ playbook_definition: async (current, _, context) => getPlaybookDefinition(context, current),
last_executions: async (current) => getLastPlaybookExecutions(current.id),
queue_messages: async (current, _, context) => getConnectorQueueSize(context, context.user, current.id)
},