pycti 6.6.0__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.6.0.dist-info → pycti-6.6.1.dist-info}/METADATA +1 -1
- {pycti-6.6.0.dist-info → pycti-6.6.1.dist-info}/RECORD +15 -10
- {pycti-6.6.0.dist-info → pycti-6.6.1.dist-info}/WHEEL +0 -0
- {pycti-6.6.0.dist-info → pycti-6.6.1.dist-info}/licenses/LICENSE +0 -0
- {pycti-6.6.0.dist-info → pycti-6.6.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,803 @@
|
|
|
1
|
+
import secrets
|
|
2
|
+
from typing import Dict, List, Optional
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class User:
|
|
6
|
+
"""Representation of a user on the OpenCTI platform
|
|
7
|
+
|
|
8
|
+
Users can be member of multiple groups, from which its permissions
|
|
9
|
+
(capabilities) are derived. Additionally, users are part of organisations,
|
|
10
|
+
and sometimes administrating them (Enterprise edition).
|
|
11
|
+
|
|
12
|
+
They have configured confidence, and an effective confidence (which might
|
|
13
|
+
be set by the group).
|
|
14
|
+
|
|
15
|
+
You can view the properties, token_properties, session_properties, and
|
|
16
|
+
me_properties attributes of a User object to view what attributes will be
|
|
17
|
+
present in a User or MeUser object.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, opencti):
|
|
21
|
+
self.opencti = opencti
|
|
22
|
+
self.properties = """
|
|
23
|
+
id
|
|
24
|
+
standard_id
|
|
25
|
+
individual_id
|
|
26
|
+
user_email
|
|
27
|
+
firstname
|
|
28
|
+
lastname
|
|
29
|
+
name
|
|
30
|
+
description
|
|
31
|
+
language
|
|
32
|
+
theme
|
|
33
|
+
unit_system
|
|
34
|
+
external
|
|
35
|
+
restrict_delete
|
|
36
|
+
account_status
|
|
37
|
+
account_lock_after_date
|
|
38
|
+
entity_type
|
|
39
|
+
parent_types
|
|
40
|
+
created_at
|
|
41
|
+
updated_at
|
|
42
|
+
unit_system
|
|
43
|
+
submenu_show_icons
|
|
44
|
+
submenu_auto_collapse
|
|
45
|
+
monochrome_labels
|
|
46
|
+
roles {
|
|
47
|
+
id, name, description
|
|
48
|
+
capabilities {
|
|
49
|
+
id, name
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
groups {
|
|
53
|
+
edges {
|
|
54
|
+
node {
|
|
55
|
+
id, name, description
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
objectOrganization {
|
|
60
|
+
edges {
|
|
61
|
+
node {
|
|
62
|
+
id, is_inferred, name, description
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
administrated_organizations {
|
|
67
|
+
id, name, description
|
|
68
|
+
}
|
|
69
|
+
user_confidence_level {
|
|
70
|
+
max_confidence
|
|
71
|
+
overrides {
|
|
72
|
+
entity_type, max_confidence
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
effective_confidence_level {
|
|
76
|
+
max_confidence
|
|
77
|
+
source {
|
|
78
|
+
type
|
|
79
|
+
object {
|
|
80
|
+
... on Group {
|
|
81
|
+
id, name
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
overrides {
|
|
86
|
+
entity_type, max_confidence
|
|
87
|
+
source {
|
|
88
|
+
type
|
|
89
|
+
object {
|
|
90
|
+
... on Group {
|
|
91
|
+
id, name
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
self.token_properties = """
|
|
100
|
+
api_token
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
self.session_properties = """
|
|
104
|
+
sessions {
|
|
105
|
+
id, created, ttl, originalMaxAge
|
|
106
|
+
}
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
self.me_properties = """
|
|
110
|
+
id
|
|
111
|
+
individual_id
|
|
112
|
+
user_email
|
|
113
|
+
firstname
|
|
114
|
+
lastname
|
|
115
|
+
name
|
|
116
|
+
description
|
|
117
|
+
theme
|
|
118
|
+
language
|
|
119
|
+
unit_system
|
|
120
|
+
submenu_show_icons
|
|
121
|
+
submenu_auto_collapse
|
|
122
|
+
entity_type
|
|
123
|
+
parent_types
|
|
124
|
+
created_at
|
|
125
|
+
updated_at
|
|
126
|
+
objectOrganization {
|
|
127
|
+
edges {
|
|
128
|
+
node {
|
|
129
|
+
id, name
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
administrated_organizations {
|
|
134
|
+
id, name
|
|
135
|
+
}
|
|
136
|
+
capabilities {
|
|
137
|
+
id, name, description
|
|
138
|
+
}
|
|
139
|
+
groups {
|
|
140
|
+
edges {
|
|
141
|
+
node {
|
|
142
|
+
id, name, description
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
effective_confidence_level {
|
|
147
|
+
max_confidence
|
|
148
|
+
source {
|
|
149
|
+
type
|
|
150
|
+
object {
|
|
151
|
+
... on Group {
|
|
152
|
+
id, name
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
overrides {
|
|
157
|
+
entity_type, max_confidence
|
|
158
|
+
source {
|
|
159
|
+
type
|
|
160
|
+
object {
|
|
161
|
+
... on Group {
|
|
162
|
+
id, name
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
def list(self, **kwargs) -> List[Dict]:
|
|
171
|
+
"""Search/list users on the platform
|
|
172
|
+
|
|
173
|
+
Searches users given some conditions. Defaults to listing all users.
|
|
174
|
+
|
|
175
|
+
:param first: Defaults to 500. Retrieve this number of results.
|
|
176
|
+
:type first: int, optional
|
|
177
|
+
:param after: Retrieves all results after the user with this ID.
|
|
178
|
+
Ignored if None, empty, or if fetching all results, defaults to
|
|
179
|
+
None.
|
|
180
|
+
:type after: str, optional
|
|
181
|
+
:param orderBy: Orders results by this field.
|
|
182
|
+
Can be one of user, user_email, firstname, lastname, language,
|
|
183
|
+
external, created_at, updated_at, or _score, defaults to "name".
|
|
184
|
+
:type orderBy: str, optional
|
|
185
|
+
:param orderMode: Ordering direction. Must be one
|
|
186
|
+
of "asc" or "desc", defaults to "asc".
|
|
187
|
+
:type orderMode: str, optional
|
|
188
|
+
:param filters: OpenCTI API FilterGroup object.
|
|
189
|
+
This is an advanced parameter. To learn more please search for
|
|
190
|
+
the FilterGroup object in the OpenCTI GraphQL Playground, defaults
|
|
191
|
+
to {}.
|
|
192
|
+
:type filters: dict, optional
|
|
193
|
+
:param search: String to search for when listing
|
|
194
|
+
users, defaults to None.
|
|
195
|
+
:type search: str, optional
|
|
196
|
+
:param include_sessions: Whether or not to
|
|
197
|
+
include a list of sessions with results, defaults to False.
|
|
198
|
+
:type include_sessions: bool, optional
|
|
199
|
+
:param customAttributes: Custom attributes to fetch from the GraphQL
|
|
200
|
+
query
|
|
201
|
+
:type customAttributes: str, optional
|
|
202
|
+
:param getAll: Defaults to False. Whether or not to get all results
|
|
203
|
+
from the search. If True then param first is ignored.
|
|
204
|
+
:type getAll: bool, optional
|
|
205
|
+
:param withPagination: Defaults to False. Whether to return pagination
|
|
206
|
+
info with results.
|
|
207
|
+
:type withPagination: bool, optional
|
|
208
|
+
:return: Returns a list of users, sorted as specified.
|
|
209
|
+
:rtype: list[dict]
|
|
210
|
+
"""
|
|
211
|
+
first = kwargs.get("first", 500)
|
|
212
|
+
after = kwargs.get("after", None)
|
|
213
|
+
order_by = kwargs.get("orderBy", "name")
|
|
214
|
+
order_mode = kwargs.get("orderMode", "asc")
|
|
215
|
+
filters = kwargs.get("filters", None)
|
|
216
|
+
search = kwargs.get("search", None)
|
|
217
|
+
include_sessions = kwargs.get("include_sessions", False)
|
|
218
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
219
|
+
get_all = kwargs.get("getAll", False)
|
|
220
|
+
with_pagination = kwargs.get("withPagination", False)
|
|
221
|
+
|
|
222
|
+
if get_all:
|
|
223
|
+
first = 100
|
|
224
|
+
|
|
225
|
+
self.opencti.admin_logger.info(
|
|
226
|
+
"Fetching users with filters", {"filters": filters}
|
|
227
|
+
)
|
|
228
|
+
query = (
|
|
229
|
+
"""
|
|
230
|
+
query UserList($first: Int, $after: ID, $orderBy: UsersOrdering, $orderMode: OrderingMode, $filters: FilterGroup, $search: String) {
|
|
231
|
+
users(first: $first, after: $after, orderBy: $orderBy, orderMode: $orderMode, filters: $filters, search: $search) {
|
|
232
|
+
edges {
|
|
233
|
+
node {
|
|
234
|
+
"""
|
|
235
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
236
|
+
+ (self.session_properties if include_sessions else "")
|
|
237
|
+
+ """
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
pageInfo {
|
|
242
|
+
startCursor, endCursor, hasNextPage, hasPreviousPage
|
|
243
|
+
globalCount
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
"""
|
|
248
|
+
)
|
|
249
|
+
result = self.opencti.query(
|
|
250
|
+
query,
|
|
251
|
+
{
|
|
252
|
+
"first": first,
|
|
253
|
+
"after": after,
|
|
254
|
+
"orderBy": order_by,
|
|
255
|
+
"orderMode": order_mode,
|
|
256
|
+
"filters": filters,
|
|
257
|
+
"search": search,
|
|
258
|
+
},
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
if get_all:
|
|
262
|
+
final_data = []
|
|
263
|
+
data = self.opencti.process_multiple(result["data"]["users"])
|
|
264
|
+
final_data = final_data + data
|
|
265
|
+
while result["data"]["users"]["pageInfo"]["hasNextPage"]:
|
|
266
|
+
after = result["data"]["users"]["pageInfo"]["endCursor"]
|
|
267
|
+
result = self.opencti.query(
|
|
268
|
+
query,
|
|
269
|
+
{
|
|
270
|
+
"first": first,
|
|
271
|
+
"after": after,
|
|
272
|
+
"orderBy": order_by,
|
|
273
|
+
"orderMode": order_mode,
|
|
274
|
+
"filters": filters,
|
|
275
|
+
"search": search,
|
|
276
|
+
},
|
|
277
|
+
)
|
|
278
|
+
data = self.opencti.process_multiple(result["data"]["users"])
|
|
279
|
+
final_data = final_data + data
|
|
280
|
+
return final_data
|
|
281
|
+
else:
|
|
282
|
+
return self.opencti.process_multiple(
|
|
283
|
+
result["data"]["users"], with_pagination
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
def read(self, **kwargs) -> Optional[Dict]:
|
|
287
|
+
"""Reads user details from the platform.
|
|
288
|
+
|
|
289
|
+
:param id: ID of the user to fetch
|
|
290
|
+
:type id: str, optional
|
|
291
|
+
:param include_sessions: Whether or not to
|
|
292
|
+
include a list of sessions for the given user, defaults to False.
|
|
293
|
+
:type include_sessions: bool, optional
|
|
294
|
+
:param include_token: Whether or not to include
|
|
295
|
+
the user's API token, defaults to False.
|
|
296
|
+
:type include_token: bool, optional
|
|
297
|
+
:param customAttributes: Custom attributes to include instead of the
|
|
298
|
+
defaults
|
|
299
|
+
:type customAttribues: str, optional
|
|
300
|
+
:param filters: Filters to apply to find a single user
|
|
301
|
+
:type filters: dict, optional
|
|
302
|
+
:param search: Search term to use to find a single user
|
|
303
|
+
:type search: str, optional
|
|
304
|
+
:return: Representation of the user as a Python dictionary.
|
|
305
|
+
:rtype: Optional[Dict]
|
|
306
|
+
"""
|
|
307
|
+
id = kwargs.get("id", None)
|
|
308
|
+
include_sessions = kwargs.get("include_sessions", False)
|
|
309
|
+
include_token = kwargs.get("include_token", False)
|
|
310
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
311
|
+
filters = kwargs.get("filters", None)
|
|
312
|
+
search = kwargs.get("search", None)
|
|
313
|
+
if id is not None:
|
|
314
|
+
self.opencti.admin_logger.info("Fetching user with ID", {"id": id})
|
|
315
|
+
query = (
|
|
316
|
+
"""
|
|
317
|
+
query UserRead($id: String!) {
|
|
318
|
+
user(id: $id) {
|
|
319
|
+
"""
|
|
320
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
321
|
+
+ (self.token_properties if include_token else "")
|
|
322
|
+
+ (self.session_properties if include_sessions else "")
|
|
323
|
+
+ """
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
"""
|
|
327
|
+
)
|
|
328
|
+
result = self.opencti.query(query, {"id": id})
|
|
329
|
+
return self.opencti.process_multiple_fields(result["data"]["user"])
|
|
330
|
+
elif filters is not None or search is not None:
|
|
331
|
+
results = self.list(
|
|
332
|
+
filters=filters,
|
|
333
|
+
search=search,
|
|
334
|
+
include_sessions=include_sessions,
|
|
335
|
+
customAttributes=custom_attributes,
|
|
336
|
+
)
|
|
337
|
+
user = results[0] if results else None
|
|
338
|
+
if not include_token or user is None:
|
|
339
|
+
return user
|
|
340
|
+
else:
|
|
341
|
+
return self.read(
|
|
342
|
+
id=user["id"],
|
|
343
|
+
include_sessions=include_sessions,
|
|
344
|
+
include_token=include_token,
|
|
345
|
+
customAttributes=custom_attributes,
|
|
346
|
+
)
|
|
347
|
+
else:
|
|
348
|
+
self.opencti.admin_logger.error(
|
|
349
|
+
"[opencti_user] Missing paramters: id, search, or filters"
|
|
350
|
+
)
|
|
351
|
+
return None
|
|
352
|
+
|
|
353
|
+
def create(self, **kwargs) -> Optional[Dict]:
|
|
354
|
+
"""Creates a new user with basic details
|
|
355
|
+
|
|
356
|
+
Note that when SSO is connected users generally do not need to be
|
|
357
|
+
manually created.
|
|
358
|
+
|
|
359
|
+
Additionally note that if there is no password passed to this function
|
|
360
|
+
then a random password will be created and will not be returned. This
|
|
361
|
+
is useful for creating service accounts and connector accounts.
|
|
362
|
+
|
|
363
|
+
:param name: Name to assign to the user.
|
|
364
|
+
:type name: str
|
|
365
|
+
:param user_email: Email address for the user.
|
|
366
|
+
:type user_email: str
|
|
367
|
+
:param password: Password that should be assigned
|
|
368
|
+
to the user. If one is not provided then a random one will be
|
|
369
|
+
generated, defaults to None.
|
|
370
|
+
:type password: str, optional
|
|
371
|
+
:param firstname: First name of the user
|
|
372
|
+
:type firstname: str, optional
|
|
373
|
+
:param lastname: Last name of the user
|
|
374
|
+
:type lastname: str, optional
|
|
375
|
+
:param description: Description for the user
|
|
376
|
+
:type description: str, optional
|
|
377
|
+
:param language: Language the user should use
|
|
378
|
+
:type language: str, optional
|
|
379
|
+
:param theme: Theme to set for the user, either light or dark
|
|
380
|
+
:type theme: str, optional
|
|
381
|
+
:param objectOrganization: List of organization IDs to add the user to
|
|
382
|
+
:type objectOgranization: List[str], optional
|
|
383
|
+
:param account_status: The status of the account: Active, Expired,
|
|
384
|
+
Inactive, or Locked
|
|
385
|
+
:type account_status: str, optional
|
|
386
|
+
:param account_lock_after_date: ISO 8901 of when account should be
|
|
387
|
+
locked
|
|
388
|
+
:type account_lock_after_date: str, optional
|
|
389
|
+
:param unit_system: Unit system for the user, metric or imperial
|
|
390
|
+
:type unit_system: str, optional
|
|
391
|
+
:param submenu_show_icons: Defaults to False. Whether or not to show
|
|
392
|
+
icons in submenus on the left hand menu bar in the UI
|
|
393
|
+
:type submenu_show_icons: bool, optional
|
|
394
|
+
:param submenu_auto_collaps: Defaults to False. Whether to auto-
|
|
395
|
+
collapse the left hand menu bar in the UI
|
|
396
|
+
:type submenu_auto_collapse: bool, optional
|
|
397
|
+
:param monochrome_labels: Defaults to False. Whether to ignore colours
|
|
398
|
+
and just show entity labels in monochrome.
|
|
399
|
+
:type monochrome_labels: bool, optional
|
|
400
|
+
:param groups: List of group IDs to add the user to
|
|
401
|
+
:type groups: List[str], optional
|
|
402
|
+
:param user_confidence_level: Confidence level object to assign to the
|
|
403
|
+
user. This may not impact effective confidence depending on group
|
|
404
|
+
membership.
|
|
405
|
+
:type user_confidence_level: Dict
|
|
406
|
+
:param customAttributes: Custom attributes to return for the user
|
|
407
|
+
:type customAttributes: str, optional
|
|
408
|
+
:param include_token: Defaults to False. Whether to include the API
|
|
409
|
+
token for the new user in the response.
|
|
410
|
+
:type include_token: bool, optional
|
|
411
|
+
:return: Representation of the user without sessions or API token.
|
|
412
|
+
:rtype: Optional[Dict]
|
|
413
|
+
"""
|
|
414
|
+
name = kwargs.get("name", None)
|
|
415
|
+
user_email = kwargs.get("user_email", None)
|
|
416
|
+
password = kwargs.get("password", None)
|
|
417
|
+
firstname = kwargs.get("firstname", None)
|
|
418
|
+
lastname = kwargs.get("lastname", None)
|
|
419
|
+
description = kwargs.get("description", None)
|
|
420
|
+
language = kwargs.get("language", None)
|
|
421
|
+
theme = kwargs.get("theme", None)
|
|
422
|
+
object_organization = kwargs.get("objectOrganization", None)
|
|
423
|
+
account_status = kwargs.get("account_status", None)
|
|
424
|
+
account_lock_after_date = kwargs.get("account_lock_after_date", None)
|
|
425
|
+
unit_system = kwargs.get("unit_system", None)
|
|
426
|
+
submenu_show_icons = kwargs.get("submenu_show_icons", False)
|
|
427
|
+
submenu_auto_collapse = kwargs.get("submenu_auto_collapse", False)
|
|
428
|
+
monochrome_labels = kwargs.get("monochrome_labels", False)
|
|
429
|
+
groups = kwargs.get("groups", None)
|
|
430
|
+
user_confidence_level = kwargs.get("user_confidence_level", None)
|
|
431
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
432
|
+
include_token = kwargs.get("include_token", False)
|
|
433
|
+
|
|
434
|
+
if name is None or user_email is None:
|
|
435
|
+
self.opencti.admin_logger.error(
|
|
436
|
+
"[opencti_user] Missing parameters: name and user_email"
|
|
437
|
+
)
|
|
438
|
+
return None
|
|
439
|
+
|
|
440
|
+
self.opencti.admin_logger.info(
|
|
441
|
+
"Creating a new user", {"name": name, "email": user_email}
|
|
442
|
+
)
|
|
443
|
+
if password is None:
|
|
444
|
+
self.opencti.admin_logger.info(
|
|
445
|
+
"Generating random password for user",
|
|
446
|
+
{"name": name, "user_email": user_email},
|
|
447
|
+
)
|
|
448
|
+
password = secrets.token_urlsafe(64)
|
|
449
|
+
query = (
|
|
450
|
+
"""
|
|
451
|
+
mutation UserAdd($input: UserAddInput!) {
|
|
452
|
+
userAdd(input: $input) {
|
|
453
|
+
"""
|
|
454
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
455
|
+
+ (self.token_properties if include_token else "")
|
|
456
|
+
+ """
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
"""
|
|
460
|
+
)
|
|
461
|
+
result = self.opencti.query(
|
|
462
|
+
query,
|
|
463
|
+
{
|
|
464
|
+
"input": {
|
|
465
|
+
"user_email": user_email,
|
|
466
|
+
"name": name,
|
|
467
|
+
"password": password,
|
|
468
|
+
"firstname": firstname,
|
|
469
|
+
"lastname": lastname,
|
|
470
|
+
"description": description,
|
|
471
|
+
"language": language,
|
|
472
|
+
"theme": theme,
|
|
473
|
+
"objectOrganization": object_organization,
|
|
474
|
+
"account_status": account_status,
|
|
475
|
+
"account_lock_after_date": account_lock_after_date,
|
|
476
|
+
"unit_system": unit_system,
|
|
477
|
+
"submenu_show_icons": submenu_show_icons,
|
|
478
|
+
"submenu_auto_collapse": submenu_auto_collapse,
|
|
479
|
+
"monochrome_labels": monochrome_labels,
|
|
480
|
+
"groups": groups,
|
|
481
|
+
"user_confidence_level": user_confidence_level,
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
)
|
|
485
|
+
return self.opencti.process_multiple_fields(result["data"]["userAdd"])
|
|
486
|
+
|
|
487
|
+
def delete(self, **kwargs):
|
|
488
|
+
"""Deletes the given user from the platform.
|
|
489
|
+
|
|
490
|
+
:param id: ID of the user to delete.
|
|
491
|
+
:type id: str
|
|
492
|
+
"""
|
|
493
|
+
id = kwargs.get("id", None)
|
|
494
|
+
if id is None:
|
|
495
|
+
self.opencti.admin_logger.error("[opencti_user] Missing parameter: id")
|
|
496
|
+
return None
|
|
497
|
+
|
|
498
|
+
self.opencti.admin_logger.info("Deleting user", {"id": id})
|
|
499
|
+
query = """
|
|
500
|
+
mutation DeleteUser($id: ID!) {
|
|
501
|
+
userEdit(id: $id) {
|
|
502
|
+
delete
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
"""
|
|
506
|
+
self.opencti.query(query, {"id": id})
|
|
507
|
+
|
|
508
|
+
def me(self, **kwargs) -> Dict:
|
|
509
|
+
"""Reads the currently authenticated user.
|
|
510
|
+
|
|
511
|
+
:param include_token: Whether to inclued the API
|
|
512
|
+
token of the currently authenticated user, defaults to False.
|
|
513
|
+
:type include_token: bool, optional
|
|
514
|
+
:param customAttributes: Custom attributes to return on the User
|
|
515
|
+
:type customAttributes: str, optional
|
|
516
|
+
:return: Representation of the user.
|
|
517
|
+
:rtype: dict
|
|
518
|
+
"""
|
|
519
|
+
include_token = kwargs.get("include_token", False)
|
|
520
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
521
|
+
|
|
522
|
+
self.opencti.admin_logger.info("Reading MeUser")
|
|
523
|
+
query = (
|
|
524
|
+
"""
|
|
525
|
+
query Me {
|
|
526
|
+
me {
|
|
527
|
+
"""
|
|
528
|
+
+ (self.me_properties if custom_attributes is None else custom_attributes)
|
|
529
|
+
+ (self.token_properties if include_token else "")
|
|
530
|
+
+ """
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
"""
|
|
534
|
+
)
|
|
535
|
+
result = self.opencti.query(query)
|
|
536
|
+
return self.opencti.process_multiple_fields(result["data"]["me"])
|
|
537
|
+
|
|
538
|
+
def update_field(self, **kwargs) -> Optional[Dict]:
|
|
539
|
+
"""Update a given user using fieldPatch
|
|
540
|
+
|
|
541
|
+
:param id: ID of the user to update.
|
|
542
|
+
:type id: str
|
|
543
|
+
:param input: FieldPatchInput objects to edit user
|
|
544
|
+
:type input: List[Dict]
|
|
545
|
+
:param customAttributes: Custom attributes to return from the mutation
|
|
546
|
+
:type customAttributes: str, optional
|
|
547
|
+
:return: Representation of the user without sessions or API token.
|
|
548
|
+
:rtype: Optional[Dict]
|
|
549
|
+
"""
|
|
550
|
+
id = kwargs.get("id", None)
|
|
551
|
+
input = kwargs.get("input", None)
|
|
552
|
+
custom_attributes = kwargs.get("customAttributes", None)
|
|
553
|
+
if id is None or input is None:
|
|
554
|
+
self.opencti.admin_logger.error(
|
|
555
|
+
"[opencti_user] Missing parameters: id and input"
|
|
556
|
+
)
|
|
557
|
+
return None
|
|
558
|
+
|
|
559
|
+
self.opencti.admin_logger.info(
|
|
560
|
+
"Editing user with input (not shown to hide password and API token"
|
|
561
|
+
" changes)",
|
|
562
|
+
{"id": id},
|
|
563
|
+
)
|
|
564
|
+
query = (
|
|
565
|
+
"""
|
|
566
|
+
mutation UserEdit($id: ID!, $input: [EditInput]!) {
|
|
567
|
+
userEdit(id: $id) {
|
|
568
|
+
fieldPatch(input: $input) {
|
|
569
|
+
"""
|
|
570
|
+
+ (self.properties if custom_attributes is None else custom_attributes)
|
|
571
|
+
+ """
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
"""
|
|
576
|
+
)
|
|
577
|
+
result = self.opencti.query(query, {"id": id, "input": input})
|
|
578
|
+
return self.opencti.process_multiple_fields(
|
|
579
|
+
result["data"]["userEdit"]["fieldPatch"]
|
|
580
|
+
)
|
|
581
|
+
|
|
582
|
+
def add_membership(self, **kwargs) -> Optional[Dict]:
|
|
583
|
+
"""Adds the user to a given group.
|
|
584
|
+
|
|
585
|
+
:param id: User ID to add to the group.
|
|
586
|
+
:type id: str
|
|
587
|
+
:param group_id: Group ID to add the user to.
|
|
588
|
+
:type group_id: str
|
|
589
|
+
:return: Representation of the InternalRelationship
|
|
590
|
+
:rtype: Optional[Dict]
|
|
591
|
+
"""
|
|
592
|
+
id = kwargs.get("id", None)
|
|
593
|
+
group_id = kwargs.get("group_id", None)
|
|
594
|
+
if id is None or group_id is None:
|
|
595
|
+
self.opencti.admin_logger.error(
|
|
596
|
+
"[opencti_user] Missing parameters: id and group_id"
|
|
597
|
+
)
|
|
598
|
+
return None
|
|
599
|
+
|
|
600
|
+
self.opencti.admin_logger.info(
|
|
601
|
+
"Adding user to group", {"id": id, "group_id": group_id}
|
|
602
|
+
)
|
|
603
|
+
query = """
|
|
604
|
+
mutation UserEditAddMembership($id: ID!, $group_id: ID!) {
|
|
605
|
+
userEdit(id: $id) {
|
|
606
|
+
relationAdd(input: {
|
|
607
|
+
relationship_type: "member-of",
|
|
608
|
+
toId: $group_id
|
|
609
|
+
}) {
|
|
610
|
+
id
|
|
611
|
+
from {
|
|
612
|
+
... on User {
|
|
613
|
+
id, name, user_email
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
to {
|
|
617
|
+
... on Group {
|
|
618
|
+
id, name, description
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
"""
|
|
625
|
+
result = self.opencti.query(query, {"id": id, "group_id": group_id})
|
|
626
|
+
return self.opencti.process_multiple_fields(
|
|
627
|
+
result["data"]["userEdit"]["relationAdd"]
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
def delete_membership(self, **kwargs) -> Optional[Dict]:
|
|
631
|
+
"""Removes the user from the given group.
|
|
632
|
+
|
|
633
|
+
:param id: User ID to remove from the group.
|
|
634
|
+
:type id: str
|
|
635
|
+
:param group_id: Group ID to remove the user from.
|
|
636
|
+
:type group_id: str
|
|
637
|
+
:return: Representation of the user without sessions or API token
|
|
638
|
+
:rtype: Optional[Dict]
|
|
639
|
+
"""
|
|
640
|
+
id = kwargs.get("id", None)
|
|
641
|
+
group_id = kwargs.get("group_id", None)
|
|
642
|
+
if id is None or group_id is None:
|
|
643
|
+
self.opencti.admin_logger.error(
|
|
644
|
+
"[opencti_user] Missing parameters: id and group_id"
|
|
645
|
+
)
|
|
646
|
+
return None
|
|
647
|
+
|
|
648
|
+
self.opencti.admin_logger.info(
|
|
649
|
+
"Removing used from group", {"id": id, "group_id": group_id}
|
|
650
|
+
)
|
|
651
|
+
query = (
|
|
652
|
+
"""
|
|
653
|
+
mutation UserEditDeleteMembership($id: ID!, $group_id: StixRef!) {
|
|
654
|
+
userEdit(id: $id) {
|
|
655
|
+
relationDelete(toId: $group_id, relationship_type: "member-of") {
|
|
656
|
+
"""
|
|
657
|
+
+ self.properties
|
|
658
|
+
+ """
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
"""
|
|
663
|
+
)
|
|
664
|
+
result = self.opencti.query(query, {"id": id, "group_id": group_id})
|
|
665
|
+
return self.opencti.process_multiple_fields(
|
|
666
|
+
result["data"]["userEdit"]["relationDelete"]
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
def add_organization(self, **kwargs) -> Optional[Dict]:
|
|
670
|
+
"""Adds a user to an organization
|
|
671
|
+
|
|
672
|
+
:param id: User ID to add to organization
|
|
673
|
+
:type id: str
|
|
674
|
+
:param organization_id: ID of organization to add to
|
|
675
|
+
:type organization_id: str
|
|
676
|
+
:return: Representation of user without sessions or API key
|
|
677
|
+
:rtype: Optional[Dict]
|
|
678
|
+
"""
|
|
679
|
+
id = kwargs.get("id", None)
|
|
680
|
+
organization_id = kwargs.get("organization_id", None)
|
|
681
|
+
if id is None or organization_id is None:
|
|
682
|
+
self.opencti.admin_logger.error(
|
|
683
|
+
"[opencti_user] Missing parameters: id and organization_id"
|
|
684
|
+
)
|
|
685
|
+
|
|
686
|
+
self.opencti.admin_logger.info(
|
|
687
|
+
"Adding user to organization",
|
|
688
|
+
{"id": id, "organization_id": organization_id},
|
|
689
|
+
)
|
|
690
|
+
query = (
|
|
691
|
+
"""
|
|
692
|
+
mutation UserEditAddOrganization($id: ID!, $organization_id: ID!) {
|
|
693
|
+
userEdit(id: $id) {
|
|
694
|
+
organizationAdd(organizationId: $organization_id) {
|
|
695
|
+
"""
|
|
696
|
+
+ self.properties
|
|
697
|
+
+ """
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
"""
|
|
702
|
+
)
|
|
703
|
+
result = self.opencti.query(
|
|
704
|
+
query, {"id": id, "organization_id": organization_id}
|
|
705
|
+
)
|
|
706
|
+
return self.opencti.process_multiple_fields(
|
|
707
|
+
result["data"]["userEdit"]["organizationAdd"]
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
def delete_organization(self, **kwargs) -> Optional[Dict]:
|
|
711
|
+
"""Delete a user from an organization
|
|
712
|
+
|
|
713
|
+
:param id: User ID to remove from organization
|
|
714
|
+
:type id: str
|
|
715
|
+
:param organization_id: ID of organization to remove from
|
|
716
|
+
:type organization_id: str
|
|
717
|
+
:return: Representation of user without sessions or API key
|
|
718
|
+
:rtype: Optional[Dict]
|
|
719
|
+
"""
|
|
720
|
+
id = kwargs.get("id", None)
|
|
721
|
+
organization_id = kwargs.get("organization_id", None)
|
|
722
|
+
if id is None or organization_id is None:
|
|
723
|
+
self.opencti.admin_logger.error(
|
|
724
|
+
"[opencti_user] Missing parameters: id and organization_id"
|
|
725
|
+
)
|
|
726
|
+
|
|
727
|
+
self.opencti.admin_logger.info(
|
|
728
|
+
"Removing user from organization",
|
|
729
|
+
{"id": id, "organization_id": organization_id},
|
|
730
|
+
)
|
|
731
|
+
query = (
|
|
732
|
+
"""
|
|
733
|
+
mutation UserEditDeleteOrganization($id: ID!, $organization_id: ID!) {
|
|
734
|
+
userEdit(id: $id) {
|
|
735
|
+
organizationDelete(organizationId: $organization_id) {
|
|
736
|
+
"""
|
|
737
|
+
+ self.properties
|
|
738
|
+
+ """
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
"""
|
|
743
|
+
)
|
|
744
|
+
result = self.opencti.query(
|
|
745
|
+
query, {"id": id, "organization_id": organization_id}
|
|
746
|
+
)
|
|
747
|
+
return self.opencti.process_multiple_fields(
|
|
748
|
+
result["data"]["userEdit"]["organizationDelete"]
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
def token_renew(self, **kwargs) -> Optional[Dict]:
|
|
752
|
+
"""Rotates the API token for the given user
|
|
753
|
+
|
|
754
|
+
:param user: User ID to rotate API token for.
|
|
755
|
+
:type user: str
|
|
756
|
+
:param include_token: Whether to include new API
|
|
757
|
+
token in response from server, defaults to False.
|
|
758
|
+
:type include_token: bool, optional
|
|
759
|
+
:return: Representation of user
|
|
760
|
+
:rtype: Optional[Dict]
|
|
761
|
+
"""
|
|
762
|
+
id = kwargs.get("id", None)
|
|
763
|
+
include_token = kwargs.get("include_token", False)
|
|
764
|
+
if id is None:
|
|
765
|
+
self.opencti.admin_logger.error("[opencti_user] Missing parameter: id")
|
|
766
|
+
return None
|
|
767
|
+
|
|
768
|
+
self.opencti.admin_logger.info("Rotating API key for user", {"id": id})
|
|
769
|
+
query = (
|
|
770
|
+
"""
|
|
771
|
+
mutation UserEditRotateToken($id: ID!) {
|
|
772
|
+
userEdit(id: $id) {
|
|
773
|
+
tokenRenew {
|
|
774
|
+
"""
|
|
775
|
+
+ self.properties
|
|
776
|
+
+ (self.token_properties if include_token else "")
|
|
777
|
+
+ """
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
"""
|
|
782
|
+
)
|
|
783
|
+
result = self.opencti.query(query, {"id": id})
|
|
784
|
+
return self.opencti.process_multiple_fields(
|
|
785
|
+
result["data"]["userEdit"]["tokenRenew"]
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
def process_multiple_fields(self, data):
|
|
789
|
+
if "roles" in data:
|
|
790
|
+
data["roles"] = self.opencti.process_multiple(data["roles"])
|
|
791
|
+
data["rolesIds"] = self.opencti.process_multiple_ids(data["roles"])
|
|
792
|
+
if "groups" in data:
|
|
793
|
+
data["groups"] = self.opencti.process_multiple(data["groups"])
|
|
794
|
+
data["groupsIds"] = self.opencti.process_multiple_ids(data["groups"])
|
|
795
|
+
if "objectOrganization" in data:
|
|
796
|
+
data["objectOrganization"] = self.opencti.process_multiple(
|
|
797
|
+
data["objectOrganization"]
|
|
798
|
+
)
|
|
799
|
+
data["objectOrganizationIds"] = self.opencti.process_multiple_ids(
|
|
800
|
+
data["objectOrganization"]
|
|
801
|
+
)
|
|
802
|
+
|
|
803
|
+
return data
|