@@ -18,7 +18,7 @@ import type { BasicStoreSettings } from '../types/settings';
18
18
import { ACCOUNT_STATUS_ACTIVE } from '../config/conf' ;
19
19
import { schemaAttributesDefinition } from '../schema/schema-attributes' ;
20
20
import { FunctionalError } from '../config/errors' ;
21
- import { isNotEmptyField , REDACTED_INFORMATION } from '../database/utils' ;
21
+ import { extractIdsFromStoreObject , isNotEmptyField , REDACTED_INFORMATION } from '../database/utils' ;
22
22
import { isStixObject } from '../schema/stixCoreObject' ;
23
23
24
24
export const DEFAULT_INVALID_CONF_VALUE = 'ChangeMe' ;
@@ -400,39 +400,101 @@ export const isOnlyOrgaAdmin = (user: AuthUser) => {
400
400
return ! isUserHasCapability ( user , SETTINGS_SET_ACCESSES ) && isUserHasCapability ( user , VIRTUAL_ORGANIZATION_ADMIN ) ;
401
401
} ;
402
402
403
- export const isOrganizationAllowed = ( element : BasicStoreCommon , user : AuthUser , settings :BasicStoreSettings ) => {
404
- const elementOrganizations = element [ RELATION_GRANTED_TO ] ?? [ ] ;
403
+ // returns all user member access ids : his id, his organizations ids (and parent organizations), his groups ids
404
+ export const computeUserMemberAccessIds = ( user : AuthUser ) => {
405
+ const memberAccessIds = [ user . id ] ;
406
+ if ( user . organizations ) {
407
+ const userOrganizationsIds = user . organizations . map ( ( org ) => org . internal_id ) ;
408
+ memberAccessIds . push ( ...userOrganizationsIds ) ;
409
+ }
410
+ if ( user . groups ) {
411
+ const userGroupsIds = user . groups . map ( ( group ) => group . internal_id ) ;
412
+ memberAccessIds . push ( ...userGroupsIds ) ;
413
+ }
414
+ if ( user . roles ) {
415
+ const userRolesIds = user . roles . map ( ( role ) => role . internal_id ) ;
416
+ memberAccessIds . push ( ...userRolesIds ) ;
417
+ }
418
+ return memberAccessIds ;
419
+ } ;
420
+
421
+ // region entity access by user
422
+
423
+ export const getUserAccessRight = ( user : AuthUser , element : any ) => {
424
+ if ( ! element . authorized_members || element . authorized_members . length === 0 ) { // no restricted user access on element
425
+ return MEMBER_ACCESS_RIGHT_ADMIN ;
426
+ }
427
+ const accessMembers = [ ...element . authorized_members ] ;
428
+ const userMemberAccessIds = computeUserMemberAccessIds ( user ) ;
429
+ const foundAccessMembers = accessMembers . filter ( ( u ) => u . id === MEMBER_ACCESS_ALL || userMemberAccessIds . includes ( u . id ) ) ;
430
+ // If user have extended capabilities, is an admin
431
+ if ( ( element . authorized_authorities ?? [ ] ) . some ( ( c : string ) => userMemberAccessIds . includes ( c ) || isUserHasCapability ( user , c ) ) ) {
432
+ return MEMBER_ACCESS_RIGHT_ADMIN ;
433
+ }
434
+ // if user is bypass, user has admin access (needed for data management usage)
435
+ if ( isBypassUser ( user ) ) {
436
+ return MEMBER_ACCESS_RIGHT_ADMIN ;
437
+ }
438
+ if ( ! foundAccessMembers . length ) { // user has no access
439
+ return null ;
440
+ }
441
+ if ( foundAccessMembers . some ( ( m ) => m . access_right === MEMBER_ACCESS_RIGHT_ADMIN ) ) {
442
+ return MEMBER_ACCESS_RIGHT_ADMIN ;
443
+ }
444
+ if ( foundAccessMembers . some ( ( m ) => m . access_right === MEMBER_ACCESS_RIGHT_EDIT ) ) {
445
+ return MEMBER_ACCESS_RIGHT_EDIT ;
446
+ }
447
+ return MEMBER_ACCESS_RIGHT_VIEW ;
448
+ } ;
449
+ export const hasAuthorizedMemberAccess = ( user : AuthUser , element : { authorized_members ?: AuthorizedMember [ ] , authorized_authorities ?: string [ ] } ) => {
450
+ const userAccessRight = getUserAccessRight ( user , element ) ;
451
+ return ! ! userAccessRight ;
452
+ } ;
405
453
454
+ const isEntityOrganizationsAllowed = (
455
+ entityInternalId : string ,
456
+ entityOrganizations : string [ ] ,
457
+ user : AuthUser ,
458
+ hasPlatformOrg : boolean ,
459
+ ) => {
406
460
// If platform organization is set
407
- if ( settings . platform_organization ) {
408
- const userOrganizations = user . organizations . map ( ( o ) => o . internal_id ) ;
461
+ if ( hasPlatformOrg ) {
462
+ const userOrganizations = user . organizations . map ( ( o ) => extractIdsFromStoreObject ( o ) ) . flat ( ) ;
409
463
410
464
// If user part of platform organization, is granted by default
411
465
if ( user . inside_platform_organization ) {
412
466
return true ;
413
467
}
414
468
// Grant access to the user individual
415
- if ( element . internal_id === user . individual_id ) {
469
+ if ( entityInternalId === user . individual_id ) {
416
470
return true ;
417
471
}
418
472
// If not, user is by design inside an organization
419
473
// If element has no current sharing organization, it can be accessed (secure by default)
420
474
// If element is shared, user must have a matching sharing organization
421
- return elementOrganizations . some ( ( r ) => userOrganizations . includes ( r ) ) ;
475
+ return entityOrganizations . some ( ( r ) => userOrganizations . includes ( r ) ) ;
422
476
}
423
477
return true ;
424
478
} ;
425
479
480
+ export const isOrganizationAllowed = ( element : BasicStoreCommon , user : AuthUser , hasPlatformOrg : boolean ) => {
481
+ const elementOrganizations = element [ RELATION_GRANTED_TO ] ?? [ ] ;
482
+ return isEntityOrganizationsAllowed ( element . internal_id , elementOrganizations , user , hasPlatformOrg ) ;
483
+ } ;
484
+
485
+ const isOrganizationUnrestrictedForEntityType = ( entityType : string ) => {
486
+ const types = [ entityType , ...getParentTypes ( entityType ) ] ;
487
+ if ( STIX_ORGANIZATIONS_UNRESTRICTED . some ( ( r ) => types . includes ( r ) ) ) {
488
+ return true ;
489
+ }
490
+ return false ;
491
+ } ;
426
492
/**
427
493
* Organization unrestricted mean that this element is visible whatever the organization the user belongs to.
428
494
* @param element
429
495
*/
430
496
export const isOrganizationUnrestricted = ( element : BasicStoreCommon ) => {
431
- const types = [ element . entity_type , ...getParentTypes ( element . entity_type ) ] ;
432
- if ( STIX_ORGANIZATIONS_UNRESTRICTED . some ( ( r ) => types . includes ( r ) ) ) {
433
- return true ;
434
- }
435
- return false ;
497
+ return isOrganizationUnrestrictedForEntityType ( element . entity_type ) ;
436
498
} ;
437
499
438
500
export const isMarkingAllowed = ( element : BasicStoreCommon , userAuthorizedMarkings : string [ ] ) => {
@@ -445,16 +507,42 @@ export const isMarkingAllowed = (element: BasicStoreCommon, userAuthorizedMarkin
445
507
446
508
export const canRequestAccess = async ( context : AuthContext , user : AuthUser , elements : Array < BasicStoreCommon > ) => {
447
509
const settings = await getEntityFromCache < BasicStoreSettings > ( context , user , ENTITY_TYPE_SETTINGS ) ;
510
+ const hasPlatformOrg = ! ! settings . platform_organization ;
448
511
const elementsThatRequiresAccess : Array < BasicStoreCommon > = [ ] ;
449
512
for ( let i = 0 ; i < elements . length ; i += 1 ) {
450
- if ( ! isOrganizationAllowed ( elements [ i ] , user , settings ) ) {
513
+ if ( ! isOrganizationAllowed ( elements [ i ] , user , hasPlatformOrg ) ) {
451
514
elementsThatRequiresAccess . push ( elements [ i ] ) ;
452
515
}
453
516
// TODO before removing ORGA_SHARING_REQUEST_FF: When it's ready check Authorized members
454
517
}
455
518
return elementsThatRequiresAccess ;
456
519
} ;
457
520
521
+ export const checkUserFilterStoreElements = (
522
+ user : AuthUser ,
523
+ element : BasicStoreCommon ,
524
+ authorizedMarkings : string [ ] ,
525
+ hasPlatformOrg : boolean
526
+ ) => {
527
+ // 1. Check markings
528
+ if ( ! isMarkingAllowed ( element , authorizedMarkings ) ) {
529
+ return false ;
530
+ }
531
+ // 2. check authorized members
532
+ if ( ! hasAuthorizedMemberAccess ( user , element ) ) {
533
+ return false ;
534
+ }
535
+ // 3. Check organizations
536
+ // Allow unrestricted entities
537
+ if ( isOrganizationUnrestricted ( element ) ) {
538
+ return true ;
539
+ }
540
+ // Check restricted elements
541
+ // either allowed by orga sharing or has authorized members access if authorized_members are defined (bypass orga sharing)
542
+ return isOrganizationAllowed ( element , user , hasPlatformOrg )
543
+ || ( element . authorized_members && element . authorized_members . length > 0 && hasAuthorizedMemberAccess ( user , element ) ) ;
544
+ } ;
545
+
458
546
export const userFilterStoreElements = async ( context : AuthContext , user : AuthUser , elements : Array < BasicStoreCommon > ) => {
459
547
const userFilterStoreElementsFn = async ( ) => {
460
548
// If user have bypass, grant access to all
@@ -463,19 +551,10 @@ export const userFilterStoreElements = async (context: AuthContext, user: AuthUs
463
551
}
464
552
// If not filter by the inner markings
465
553
const settings = await getEntityFromCache < BasicStoreSettings > ( context , user , ENTITY_TYPE_SETTINGS ) ;
554
+ const hasPlatformOrg = ! ! settings . platform_organization ;
466
555
const authorizedMarkings = user . allowed_marking . map ( ( a ) => a . internal_id ) ;
467
556
return elements . filter ( ( element ) => {
468
- // 1. Check markings
469
- if ( ! isMarkingAllowed ( element , authorizedMarkings ) ) {
470
- return false ;
471
- }
472
- // 2. Check organizations
473
- // Allow unrestricted entities
474
- if ( isOrganizationUnrestricted ( element ) ) {
475
- return true ;
476
- }
477
- // Check restricted elements
478
- return isOrganizationAllowed ( element , user , settings ) ;
557
+ return checkUserFilterStoreElements ( user , element , authorizedMarkings , hasPlatformOrg ) ;
479
558
} ) ;
480
559
} ;
481
560
return telemetry ( context , user , 'FILTERING store filter' , {
@@ -489,7 +568,7 @@ export const isUserCanAccessStoreElement = async (context: AuthContext, user: Au
489
568
return elements . length === 1 ;
490
569
} ;
491
570
492
- export const isUserCanAccessStixElement = async ( context : AuthContext , user : AuthUser , instance : StixObject ) => {
571
+ export const checkUserCanAccessStixElement = ( user : AuthUser , instance : StixObject , hasPlatformOrg : boolean ) => {
493
572
// If user have bypass, grant access to all
494
573
if ( isBypassUser ( user ) ) {
495
574
return true ;
@@ -503,51 +582,33 @@ export const isUserCanAccessStixElement = async (context: AuthContext, user: Aut
503
582
return false ;
504
583
}
505
584
}
506
- // 2. Check organizations
585
+ const authorized_members = instance . extensions ?. [ STIX_EXT_OCTI ] ?. authorized_members ?? [ ] ;
586
+ const authorizedMemberAllowed = hasAuthorizedMemberAccess ( user , { authorized_members } ) ;
587
+ // 2. check authorized members
588
+ if ( ! authorizedMemberAllowed ) {
589
+ return false ;
590
+ }
591
+ // 3. Check organizations
507
592
// Allow unrestricted entities
508
593
const entityType = instance . extensions ?. [ STIX_EXT_OCTI ] ?. type ?? generateInternalType ( instance ) ;
509
- const types = [ entityType , ...getParentTypes ( entityType ) ] ;
510
- if ( STIX_ORGANIZATIONS_UNRESTRICTED . some ( ( r ) => types . includes ( r ) ) ) {
594
+ if ( isOrganizationUnrestrictedForEntityType ( entityType ) ) {
511
595
return true ;
512
596
}
513
597
// Check restricted elements
514
- const settings = await getEntityFromCache < BasicStoreSettings > ( context , user , ENTITY_TYPE_SETTINGS ) ;
515
598
const elementOrganizations = instance . extensions ?. [ STIX_EXT_OCTI ] ?. granted_refs ?? [ ] ;
516
- const userOrganizations = user . organizations . map ( ( o ) => o . standard_id ) ;
517
- // If platform organization is set
518
- if ( settings . platform_organization ) {
519
- // If user part of platform organization, is granted by default
520
- if ( user . inside_platform_organization ) {
521
- return true ;
522
- }
523
- // If not, user is by design inside an organization
524
- // If element has no current sharing organization, it can be accessed (secure by default)
525
- // If element is shared, user must have a matching sharing organization
526
- return elementOrganizations . some ( ( r ) => userOrganizations . includes ( r ) ) ;
527
- }
528
- // If no platform organization is set, user can access
529
- return true ;
599
+ const organizationAllowed = isEntityOrganizationsAllowed ( instance . id , elementOrganizations , user , hasPlatformOrg ) ;
600
+ // either allowed by organization or authorized members
601
+ return organizationAllowed || ( authorized_members . length > 0 && authorizedMemberAllowed ) ;
530
602
} ;
531
603
532
- // region member access
533
-
534
- // returns all user member access ids : his id, his organizations ids (and parent organizations), his groups ids
535
- export const computeUserMemberAccessIds = ( user : AuthUser ) => {
536
- const memberAccessIds = [ user . id ] ;
537
- if ( user . organizations ) {
538
- const userOrganizationsIds = user . organizations . map ( ( org ) => org . internal_id ) ;
539
- memberAccessIds . push ( ...userOrganizationsIds ) ;
540
- }
541
- if ( user . groups ) {
542
- const userGroupsIds = user . groups . map ( ( group ) => group . internal_id ) ;
543
- memberAccessIds . push ( ...userGroupsIds ) ;
544
- }
545
- if ( user . roles ) {
546
- const userRolesIds = user . roles . map ( ( role ) => role . internal_id ) ;
547
- memberAccessIds . push ( ...userRolesIds ) ;
548
- }
549
- return memberAccessIds ;
604
+ export const isUserCanAccessStixElement = async ( context : AuthContext , user : AuthUser , instance : StixObject ) => {
605
+ const settings = await getEntityFromCache < BasicStoreSettings > ( context , user , ENTITY_TYPE_SETTINGS ) ;
606
+ const hasPlatformOrg = ! ! settings . platform_organization ;
607
+ return checkUserCanAccessStixElement ( user , instance , hasPlatformOrg ) ;
550
608
} ;
609
+ // end region
610
+
611
+ // region member access
551
612
552
613
// user access methods
553
614
export const isDirectAdministrator = ( user : AuthUser , element : any ) => {
@@ -557,32 +618,6 @@ export const isDirectAdministrator = (user: AuthUser, element: any) => {
557
618
const userMemberAccessIds = computeUserMemberAccessIds ( user ) ;
558
619
return elementAccessIds . some ( ( a : string ) => userMemberAccessIds . includes ( a ) ) ;
559
620
} ;
560
- export const getUserAccessRight = ( user : AuthUser , element : any ) => {
561
- if ( ! element . authorized_members || element . authorized_members . length === 0 ) { // no restricted user access on element
562
- return MEMBER_ACCESS_RIGHT_ADMIN ;
563
- }
564
- const accessMembers = [ ...element . authorized_members ] ;
565
- const userMemberAccessIds = computeUserMemberAccessIds ( user ) ;
566
- const foundAccessMembers = accessMembers . filter ( ( u ) => u . id === MEMBER_ACCESS_ALL || userMemberAccessIds . includes ( u . id ) ) ;
567
- // If user have extended capabilities, is an admin
568
- if ( ( element . authorized_authorities ?? [ ] ) . some ( ( c : string ) => userMemberAccessIds . includes ( c ) || isUserHasCapability ( user , c ) ) ) {
569
- return MEMBER_ACCESS_RIGHT_ADMIN ;
570
- }
571
- // if user is bypass, user has admin access (needed for data management usage)
572
- if ( isBypassUser ( user ) ) {
573
- return MEMBER_ACCESS_RIGHT_ADMIN ;
574
- }
575
- if ( ! foundAccessMembers . length ) { // user has no access
576
- return null ;
577
- }
578
- if ( foundAccessMembers . some ( ( m ) => m . access_right === MEMBER_ACCESS_RIGHT_ADMIN ) ) {
579
- return MEMBER_ACCESS_RIGHT_ADMIN ;
580
- }
581
- if ( foundAccessMembers . some ( ( m ) => m . access_right === MEMBER_ACCESS_RIGHT_EDIT ) ) {
582
- return MEMBER_ACCESS_RIGHT_EDIT ;
583
- }
584
- return MEMBER_ACCESS_RIGHT_VIEW ;
585
- } ;
586
621
587
622
// ensure that user can access the element (operation: edit / delete / manage-access)
588
623
export const validateUserAccessOperation = ( user : AuthUser , element : any , operation : 'edit' | 'delete' | 'manage-access' | 'manage-authorities-access' ) => {
0 commit comments