pycti 6.6.0__py3-none-any.whl → 6.6.2__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.

@@ -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