pycti 6.5.11__py3-none-any.whl → 6.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pycti might be problematic. Click here for more details.
- pycti/__init__.py +13 -1
- pycti/api/opencti_api_client.py +13 -0
- pycti/connector/opencti_connector_helper.py +24 -6
- pycti/entities/opencti_capability.py +52 -0
- pycti/entities/opencti_group.py +716 -0
- pycti/entities/opencti_indicator.py +6 -0
- pycti/entities/opencti_role.py +408 -0
- pycti/entities/opencti_settings.py +385 -0
- pycti/entities/opencti_user.py +803 -0
- pycti/utils/opencti_stix2.py +90 -22
- {pycti-6.5.11.dist-info → pycti-6.6.1.dist-info}/METADATA +1 -1
- {pycti-6.5.11.dist-info → pycti-6.6.1.dist-info}/RECORD +15 -10
- {pycti-6.5.11.dist-info → pycti-6.6.1.dist-info}/WHEEL +0 -0
- {pycti-6.5.11.dist-info → pycti-6.6.1.dist-info}/licenses/LICENSE +0 -0
- {pycti-6.5.11.dist-info → pycti-6.6.1.dist-info}/top_level.txt +0 -0
|
@@ -408,6 +408,12 @@ class Indicator:
|
|
|
408
408
|
stix_object["x_opencti_workflow_id"] = (
|
|
409
409
|
self.opencti.get_attribute_in_extension("workflow_id", stix_object)
|
|
410
410
|
)
|
|
411
|
+
if "x_mitre_platforms" not in stix_object:
|
|
412
|
+
stix_object["x_mitre_platforms"] = (
|
|
413
|
+
self.opencti.get_attribute_in_mitre_extension(
|
|
414
|
+
"platforms", stix_object
|
|
415
|
+
)
|
|
416
|
+
)
|
|
411
417
|
|
|
412
418
|
return self.create(
|
|
413
419
|
stix_id=stix_object["id"],
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
from typing import Dict, List, Optional
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Role:
|
|
5
|
+
"""Representation of a role in OpenCTI
|
|
6
|
+
|
|
7
|
+
Roles can have capabilities. Groups have roles, and the combined
|
|
8
|
+
capabilities of those roles determine what a group of users can do on the
|
|
9
|
+
platform.
|
|
10
|
+
|
|
11
|
+
Check the properties attribute of the class to understand what default
|
|
12
|
+
properties are fetched.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, opencti):
|
|
16
|
+
self.opencti = opencti
|
|
17
|
+
self.properties = """
|
|
18
|
+
id
|
|
19
|
+
standard_id
|
|
20
|
+
entity_type
|
|
21
|
+
parent_types
|
|
22
|
+
name
|
|
23
|
+
description
|
|
24
|
+
created_at
|
|
25
|
+
updated_at
|
|
26
|
+
capabilities {
|
|
27
|
+
id
|
|
28
|
+
name
|
|
29
|
+
description
|
|
30
|
+
}
|
|
31
|
+
can_manage_sensitive_config
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def list(self, **kwargs) -> List[Dict]:
|
|
35
|
+
"""Search or list the roles on the server.
|
|
36
|
+
|
|
37
|
+
:param search:
|
|
38
|
+
Defaults to None.
|
|
39
|
+
:type search: str, optional
|
|
40
|
+
:param first: Defaults to 500 Return the first x results from ID or
|
|
41
|
+
beginning if $after is not specified.
|
|
42
|
+
:type first: int, optional
|
|
43
|
+
:param after: Return all results after the given ID, useful for
|
|
44
|
+
pagination. Ignored if returning all results, defaults to None.
|
|
45
|
+
:type after: str, optional
|
|
46
|
+
:param orderBy: Field to order by. Must be one of "name",
|
|
47
|
+
"created_at", "updated_at", or "_score". Defaults
|
|
48
|
+
to "name", defaults to "name".
|
|
49
|
+
:type orderBy: str, optional
|
|
50
|
+
:param orderMode: Direction to order in, either "asc" or "desc",
|
|
51
|
+
defaults to "asc".
|
|
52
|
+
:type orderMode: str, optional
|
|
53
|
+
:param customAttributes: Defaults to None. Custom attributes to return
|
|
54
|
+
from query. If None, defaults are used.
|
|
55
|
+
:type customAttributes: str, optional
|
|
56
|
+
:param getAll: Defaults to False. Retrieve all results. If true then
|
|
57
|
+
the "first" param is ignored.
|
|
58
|
+
:type getAll: bool, optional
|
|
59
|
+
:param withPagination: Defaults to False Whether to include pagination
|
|
60
|
+
pageInfo properties in result.
|
|
61
|
+
:type withPagination: bool, optional
|
|
62
|
+
|
|
63
|
+
:return: List of Python dictionaries with the properties of the role.
|
|
64
|
+
:rtype: List[Dict]
|
|
65
|
+
"""
|
|
66
|
+
search = kwargs.get("search", None)
|
|
67
|
+
first = kwargs.get("first", 500)
|
|
68
|
+
after = kwargs.get("after", None)
|
|
69
|
+
order_by = kwargs.get("orderBy", None)
|
|
70
|
+
order_mode = kwargs.get("orderMode", None)
|
|
71
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
72
|
+
get_all = kwargs.get("getAll", False)
|
|
73
|
+
with_pagination = kwargs.get("withPagination", False)
|
|
74
|
+
|
|
75
|
+
self.opencti.admin_logger.info(
|
|
76
|
+
"Searching roles matching search term", {"search": search}
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if get_all:
|
|
80
|
+
first = 100
|
|
81
|
+
|
|
82
|
+
query = (
|
|
83
|
+
"""
|
|
84
|
+
query RoleList($first: Int, $after: ID, $orderBy: RolesOrdering, $orderMode: OrderingMode, $search: String) {
|
|
85
|
+
roles(first: $first, after: $after, orderBy: $orderBy, orderMode: $orderMode, search: $search) {
|
|
86
|
+
edges {
|
|
87
|
+
node {
|
|
88
|
+
"""
|
|
89
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
90
|
+
+ """
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
pageInfo {
|
|
94
|
+
startCursor
|
|
95
|
+
endCursor
|
|
96
|
+
hasNextPage
|
|
97
|
+
hasPreviousPage
|
|
98
|
+
globalCount
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
"""
|
|
103
|
+
)
|
|
104
|
+
result = self.opencti.query(
|
|
105
|
+
query,
|
|
106
|
+
{
|
|
107
|
+
"first": first,
|
|
108
|
+
"after": after,
|
|
109
|
+
"orderBy": order_by,
|
|
110
|
+
"orderMode": order_mode,
|
|
111
|
+
"search": search,
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
|
+
if get_all:
|
|
115
|
+
final_data = []
|
|
116
|
+
data = self.opencti.process_multiple(result["data"]["roles"])
|
|
117
|
+
final_data = final_data + data
|
|
118
|
+
while result["data"]["roles"]["pageInfo"]["hasNextPage"]:
|
|
119
|
+
after = result["data"]["roles"]["pageInfo"]["endCursor"]
|
|
120
|
+
result = self.opencti.query(
|
|
121
|
+
query,
|
|
122
|
+
{
|
|
123
|
+
"first": first,
|
|
124
|
+
"after": after,
|
|
125
|
+
"orderBy": order_by,
|
|
126
|
+
"orderMode": order_mode,
|
|
127
|
+
"search": search,
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
data = self.opencti.process_multiple(result["data"]["roles"])
|
|
131
|
+
final_data = final_data + data
|
|
132
|
+
return final_data
|
|
133
|
+
else:
|
|
134
|
+
return self.opencti.process_multiple(
|
|
135
|
+
result["data"]["roles"], with_pagination
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def read(self, **kwargs) -> Optional[Dict]:
|
|
139
|
+
"""Get a role given its ID or a search term
|
|
140
|
+
|
|
141
|
+
One of id or search must be provided.
|
|
142
|
+
|
|
143
|
+
:param id: ID of the role on the platform
|
|
144
|
+
:type id: str, optional
|
|
145
|
+
:param search: Search term for a role, e.g. its name
|
|
146
|
+
:type search: str, optional
|
|
147
|
+
:param customAttributes: Custom attributes on the role to return
|
|
148
|
+
:type customAttributes: str, optional
|
|
149
|
+
|
|
150
|
+
:return: Representation of the role
|
|
151
|
+
:rtype: Optional[Dict]
|
|
152
|
+
"""
|
|
153
|
+
id = kwargs.get("id", None)
|
|
154
|
+
search = kwargs.get("search", None)
|
|
155
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
156
|
+
|
|
157
|
+
if id is not None:
|
|
158
|
+
self.opencti.admin_logger.info("Reading role", {"id": id})
|
|
159
|
+
query = (
|
|
160
|
+
"""
|
|
161
|
+
query RoleRead($id: String!) {
|
|
162
|
+
role(id: $id) {
|
|
163
|
+
"""
|
|
164
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
165
|
+
+ """
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
"""
|
|
169
|
+
)
|
|
170
|
+
result = self.opencti.query(query, {"id": id})
|
|
171
|
+
return self.opencti.process_multiple_fields(result["data"]["role"])
|
|
172
|
+
elif search is not None:
|
|
173
|
+
result = self.list(search=search)
|
|
174
|
+
return result[0] if len(result) > 0 else None
|
|
175
|
+
else:
|
|
176
|
+
self.opencti.admin_logger.error(
|
|
177
|
+
"[opencti_role] Missing parameters: id or search"
|
|
178
|
+
)
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
def delete(self, **kwargs):
|
|
182
|
+
"""Delete a role given its ID
|
|
183
|
+
|
|
184
|
+
:param id: ID for the role on the platform.
|
|
185
|
+
:type id: str
|
|
186
|
+
"""
|
|
187
|
+
id = kwargs.get("id", None)
|
|
188
|
+
|
|
189
|
+
if id is None:
|
|
190
|
+
self.opencti.admin_logger.error("[opencti_role] Missing parameter: id")
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
self.opencti.admin_logger.info("Deleting role", {"id": id})
|
|
194
|
+
query = """
|
|
195
|
+
mutation RoleDelete($id: ID!) {
|
|
196
|
+
roleEdit(id: $id) {
|
|
197
|
+
delete
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
"""
|
|
201
|
+
self.opencti.query(query, {"id": id})
|
|
202
|
+
|
|
203
|
+
def create(self, **kwargs) -> Optional[Dict]:
|
|
204
|
+
"""Add a new role to OpenCTI.
|
|
205
|
+
|
|
206
|
+
:param name: Name to assign to the role.
|
|
207
|
+
:type name: str
|
|
208
|
+
:param description: Optional. Description of the role, defaults to
|
|
209
|
+
None.
|
|
210
|
+
:type description: str, optional
|
|
211
|
+
:param customAttributes: Custom attributes to return on role
|
|
212
|
+
:type customAttributes: str, optional
|
|
213
|
+
:return: Representation of the role.
|
|
214
|
+
:rtype: Optional[Dict]
|
|
215
|
+
"""
|
|
216
|
+
name = kwargs.get("name", None)
|
|
217
|
+
description = kwargs.get("description", None)
|
|
218
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
219
|
+
|
|
220
|
+
if name is None:
|
|
221
|
+
self.opencti.admin_logger.error("[opencti_role] Missing parameter: name")
|
|
222
|
+
return None
|
|
223
|
+
|
|
224
|
+
self.opencti.admin_logger.info(
|
|
225
|
+
"Creating new role", {"name": name, "description": description}
|
|
226
|
+
)
|
|
227
|
+
query = (
|
|
228
|
+
"""
|
|
229
|
+
mutation RoleCreate($input: RoleAddInput!) {
|
|
230
|
+
roleAdd(input: $input) {
|
|
231
|
+
"""
|
|
232
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
233
|
+
+ """
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
"""
|
|
237
|
+
)
|
|
238
|
+
result = self.opencti.query(
|
|
239
|
+
query, {"input": {"name": name, "description": description}}
|
|
240
|
+
)
|
|
241
|
+
return self.opencti.process_multiple_fields(result["data"]["roleAdd"])
|
|
242
|
+
|
|
243
|
+
def update_field(self, **kwargs) -> Optional[Dict]:
|
|
244
|
+
"""Updates a given role with the given inputs
|
|
245
|
+
|
|
246
|
+
Example of input::
|
|
247
|
+
|
|
248
|
+
[
|
|
249
|
+
{
|
|
250
|
+
"key": "name",
|
|
251
|
+
"value": "NewCustomRole"
|
|
252
|
+
},
|
|
253
|
+
{
|
|
254
|
+
"key": "can_manage_sensitive_config",
|
|
255
|
+
"value": False
|
|
256
|
+
}
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
:param id: ID for the role on the platform
|
|
260
|
+
:type id: str
|
|
261
|
+
:param input: List of EditInput objects
|
|
262
|
+
:type input: List[Dict]
|
|
263
|
+
:param customAttributes: Custom attributes to return on the role
|
|
264
|
+
:type customAttributes: str, optional
|
|
265
|
+
|
|
266
|
+
:return: Representation of the role
|
|
267
|
+
:rtype: Optional[Dict]
|
|
268
|
+
"""
|
|
269
|
+
id = kwargs.get("id", None)
|
|
270
|
+
input = kwargs.get("input", None)
|
|
271
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
272
|
+
|
|
273
|
+
if id is None or input is None:
|
|
274
|
+
self.opencti.admin_logger.error(
|
|
275
|
+
"[opencti_role] Missing parameters: id and input"
|
|
276
|
+
)
|
|
277
|
+
return None
|
|
278
|
+
|
|
279
|
+
self.opencti.admin_logger.info(
|
|
280
|
+
"Editing role with input", {"id": id, "input": input}
|
|
281
|
+
)
|
|
282
|
+
query = (
|
|
283
|
+
"""
|
|
284
|
+
mutation RoleUpdate($id: ID!, $input: [EditInput]!) {
|
|
285
|
+
roleEdit(id: $id) {
|
|
286
|
+
fieldPatch(input: $input) {
|
|
287
|
+
"""
|
|
288
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
289
|
+
+ """
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
"""
|
|
294
|
+
)
|
|
295
|
+
result = self.opencti.query(query, {"id": id, "input": input})
|
|
296
|
+
return self.opencti.process_multiple_fields(
|
|
297
|
+
result["data"]["roleEdit"]["fieldPatch"]
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
def add_capability(self, **kwargs) -> Optional[Dict]:
|
|
301
|
+
"""Adds a capability to a role
|
|
302
|
+
|
|
303
|
+
:param id: ID of the role.
|
|
304
|
+
:type id: str
|
|
305
|
+
:param capability_id: ID of the capability to add.
|
|
306
|
+
:type capability_id: str
|
|
307
|
+
:return: Representation of the relationship, including the role and
|
|
308
|
+
capability
|
|
309
|
+
:rtype: Optional[Dict]
|
|
310
|
+
"""
|
|
311
|
+
id = kwargs.get("id", None)
|
|
312
|
+
capability_id = kwargs.get("capability_id", None)
|
|
313
|
+
|
|
314
|
+
if id is None or capability_id is None:
|
|
315
|
+
self.opencti.admin_logger(
|
|
316
|
+
"[opencti_role] Missing parameters: id and capability_id"
|
|
317
|
+
)
|
|
318
|
+
return None
|
|
319
|
+
|
|
320
|
+
self.opencti.admin_logger.info(
|
|
321
|
+
"Adding capability to role", {"roleId": id, "capabilityId": capability_id}
|
|
322
|
+
)
|
|
323
|
+
query = (
|
|
324
|
+
"""
|
|
325
|
+
mutation RoleEditAddCapability($id: ID!, $input: InternalRelationshipAddInput!) {
|
|
326
|
+
roleEdit(id: $id) {
|
|
327
|
+
relationAdd(input: $input) {
|
|
328
|
+
id
|
|
329
|
+
entity_type
|
|
330
|
+
parent_types
|
|
331
|
+
created_at
|
|
332
|
+
updated_at
|
|
333
|
+
from {
|
|
334
|
+
... on Role {
|
|
335
|
+
"""
|
|
336
|
+
+ self.properties
|
|
337
|
+
+ """
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
to {
|
|
341
|
+
... on Capability {
|
|
342
|
+
id, name, description
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
"""
|
|
349
|
+
)
|
|
350
|
+
result = self.opencti.query(
|
|
351
|
+
query,
|
|
352
|
+
{
|
|
353
|
+
"id": id,
|
|
354
|
+
"input": {"relationship_type": "has-capability", "toId": capability_id},
|
|
355
|
+
},
|
|
356
|
+
)
|
|
357
|
+
return self.opencti.process_multiple_fields(
|
|
358
|
+
result["data"]["roleEdit"]["relationAdd"]
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
def delete_capability(self, **kwargs) -> Optional[Dict]:
|
|
362
|
+
"""Removes a capability from a role
|
|
363
|
+
|
|
364
|
+
:param id: ID of the role
|
|
365
|
+
:type id: str
|
|
366
|
+
:param capability_id: ID of the capability to remove
|
|
367
|
+
:type capability_id: str
|
|
368
|
+
:return: Representation of the role after removing the capability
|
|
369
|
+
:rtype: Optional[Dict]
|
|
370
|
+
"""
|
|
371
|
+
id = kwargs.get("id", None)
|
|
372
|
+
capability_id = kwargs.get("capability_id", None)
|
|
373
|
+
|
|
374
|
+
if id is None or capability_id is None:
|
|
375
|
+
self.opencti.admin_logger.error(
|
|
376
|
+
"[opencti_role] Missing parameters: id and capability_id"
|
|
377
|
+
)
|
|
378
|
+
return None
|
|
379
|
+
|
|
380
|
+
self.opencti.admin_logger.info(
|
|
381
|
+
"Removing capability from role",
|
|
382
|
+
{"roleId": id, "capabilityId": capability_id},
|
|
383
|
+
)
|
|
384
|
+
query = (
|
|
385
|
+
"""
|
|
386
|
+
mutation RoleEditDeleteCapability($id: ID!, $toId: StixRef!) {
|
|
387
|
+
roleEdit(id: $id) {
|
|
388
|
+
relationDelete(toId: $toId, relationship_type: "has-capability") {
|
|
389
|
+
"""
|
|
390
|
+
+ self.properties
|
|
391
|
+
+ """
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
"""
|
|
396
|
+
)
|
|
397
|
+
result = self.opencti.query(query, {"id": id, "toId": capability_id})
|
|
398
|
+
return self.opencti.process_multiple_fields(
|
|
399
|
+
result["data"]["roleEdit"]["relationDelete"]
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
def process_multiple_fields(self, data):
|
|
403
|
+
if "capabilities" in data:
|
|
404
|
+
data["capabilities"] = self.opencti.process_multiple(data["capabilities"])
|
|
405
|
+
data["capabilitiesIds"] = self.opencti.process_multiple_ids(
|
|
406
|
+
data["capabilities"]
|
|
407
|
+
)
|
|
408
|
+
return data
|