22
22
23
23
import java .util .*;
24
24
import java .util .concurrent .ConcurrentHashMap ;
25
+ import java .util .stream .Collectors ;
25
26
26
27
@ Service
27
28
public class AccessRuleService {
@@ -386,11 +387,11 @@ public boolean extractAndCheckRule(AccessRule accessRule, Object parsedRequestBo
386
387
}
387
388
388
389
if (accessRuleType == AccessRule .TypeNaming .IS_EMPTY
389
- || accessRuleType == AccessRule .TypeNaming .IS_NOT_EMPTY ) {
390
+ || accessRuleType == AccessRule .TypeNaming .IS_NOT_EMPTY ) {
390
391
if (requestBodyValue == null
391
- || (requestBodyValue instanceof String && ((String ) requestBodyValue ).isEmpty ())
392
- || (requestBodyValue instanceof Collection && ((Collection ) requestBodyValue ).isEmpty ())
393
- || (requestBodyValue instanceof Map && ((Map ) requestBodyValue ).isEmpty ())) {
392
+ || (requestBodyValue instanceof String && ((String ) requestBodyValue ).isEmpty ())
393
+ || (requestBodyValue instanceof Collection && ((Collection ) requestBodyValue ).isEmpty ())
394
+ || (requestBodyValue instanceof Map && ((Map ) requestBodyValue ).isEmpty ())) {
394
395
return accessRuleType == AccessRule .TypeNaming .IS_EMPTY ;
395
396
} else {
396
397
return accessRuleType == AccessRule .TypeNaming .IS_NOT_EMPTY ;
@@ -428,7 +429,7 @@ private boolean evaluateMap(Object requestBodyValue, AccessRule accessRule) {
428
429
return true ;
429
430
430
431
if ((accessRule .getCheckMapKeyOnly () == null || !accessRule .getCheckMapKeyOnly ())
431
- && evaluateNode (entry .getValue (), accessRule ))
432
+ && evaluateNode (entry .getValue (), accessRule ))
432
433
return true ;
433
434
}
434
435
return false ;
@@ -451,7 +452,7 @@ && evaluateNode(entry.getValue(), accessRule))
451
452
return false ;
452
453
453
454
if ((accessRule .getCheckMapKeyOnly () == null || !accessRule .getCheckMapKeyOnly ())
454
- && !evaluateNode (entry .getValue (), accessRule ))
455
+ && !evaluateNode (entry .getValue (), accessRule ))
455
456
return false ;
456
457
}
457
458
@@ -581,55 +582,51 @@ private boolean _decisionMaker(AccessRule accessRule, String requestBodyValue, S
581
582
* @param projectAlias The project alias.
582
583
*/
583
584
protected void configureAccessRule (AccessRule ar , String studyIdentifier , String consent_group , String conceptPath , String projectAlias ) {
584
- if (ar .getGates () == null ) {
585
- ar .setGates (new HashSet <>());
586
- ar .getGates ().addAll (getGates (true , false , false ));
585
+ ar .setGates (new HashSet <>());
586
+ ar .getGates ().addAll (getGates (true , false , false ));
587
587
588
- if (ar .getSubAccessRule () == null ) {
589
- ar .setSubAccessRule (new HashSet <>());
590
- }
591
- ar .getSubAccessRule ().addAll (getAllowedQueryTypeRules ());
592
- ar .getSubAccessRule ().addAll (getPhenotypeSubRules (studyIdentifier , conceptPath , projectAlias ));
593
- ar .getSubAccessRule ().addAll (getTopmedRestrictedSubRules ());
588
+ if (ar .getSubAccessRule () == null ) {
589
+ ar .setSubAccessRule (new HashSet <>());
594
590
}
591
+ addUniqueSubRules (ar , getAllowedQueryTypeRules ());
592
+ addUniqueSubRules (ar , getPhenotypeSubRules (studyIdentifier , conceptPath , projectAlias ));
593
+ addUniqueSubRules (ar , getTopmedRestrictedSubRules ());
595
594
}
596
595
596
+
597
597
/**
598
598
* Configures the harmonized AccessRule with gates and sub-rules.
599
599
*
600
600
* @param ar The AccessRule to configure.
601
601
* @param studyIdentifier The study identifier.
602
602
* @param conceptPath The concept path.
603
603
* @param projectAlias The project alias.
604
- * @return
605
604
*/
606
605
protected void configureHarmonizedAccessRule (AccessRule ar , String studyIdentifier , String conceptPath , String projectAlias ) {
607
- if (ar .getGates () == null ) {
608
- ar .setGates (new HashSet <>());
609
- ar .getGates ().add (upsertConsentGate ("HARMONIZED_CONSENT" , "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]" , true , "harmonized data" ));
606
+ ar .setGates (new HashSet <>());
607
+ ar .getGates ().add (upsertConsentGate ("HARMONIZED_CONSENT" , "$.query.query.categoryFilters." + fence_harmonized_consent_group_concept_path + "[*]" , true , "harmonized data" ));
610
608
611
- if (ar .getSubAccessRule () == null ) {
612
- ar .setSubAccessRule (new HashSet <>());
613
- }
614
- ar .getSubAccessRule ().addAll (getAllowedQueryTypeRules ());
615
- ar .getSubAccessRule ().addAll (getHarmonizedSubRules ());
616
- ar .getSubAccessRule ().addAll (getPhenotypeSubRules (studyIdentifier , conceptPath , projectAlias ));
609
+ if (ar .getSubAccessRule () == null ) {
610
+ ar .setSubAccessRule (new HashSet <>());
617
611
}
612
+
613
+ addUniqueSubRules (ar , getAllowedQueryTypeRules ());
614
+ addUniqueSubRules (ar , getHarmonizedSubRules ());
615
+ addUniqueSubRules (ar , getPhenotypeSubRules (studyIdentifier , conceptPath , projectAlias ));
618
616
}
619
617
620
618
protected AccessRule configureClinicalAccessRuleWithPhenoSubRule (AccessRule ar , String studyIdentifier , String consent_group , String conceptPath , String projectAlias ) {
621
- if (ar .getGates () == null ) {
622
- ar .setGates (new HashSet <>());
623
- ar .getGates ().addAll (getGates (true , false , true ));
619
+ ar .setGates (new HashSet <>());
620
+ ar .getGates ().addAll (getGates (true , false , true ));
624
621
625
- if (ar .getSubAccessRule () == null ) {
626
- ar .setSubAccessRule (new HashSet <>());
627
- }
628
- ar .getSubAccessRule ().addAll (getAllowedQueryTypeRules ());
629
- ar .getSubAccessRule ().addAll (getPhenotypeSubRules (studyIdentifier , conceptPath , projectAlias ));
630
- ar .getSubAccessRule ().add (createPhenotypeSubRule (fence_topmed_consent_group_concept_path , "ALLOW_TOPMED_CONSENT" , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "" , true ));
622
+ if (ar .getSubAccessRule () == null ) {
623
+ ar .setSubAccessRule (new HashSet <>());
631
624
}
632
625
626
+ addUniqueSubRules (ar , getAllowedQueryTypeRules ());
627
+ addUniqueSubRules (ar , getPhenotypeSubRules (studyIdentifier , conceptPath , projectAlias ));
628
+ addUniqueSubRules (ar , Collections .singleton (createPhenotypeSubRule (fence_topmed_consent_group_concept_path , "ALLOW_TOPMED_CONSENT" , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "" , true )));
629
+
633
630
return ar ;
634
631
}
635
632
@@ -678,7 +675,6 @@ private Set<AccessRule> loadAllowedQueryTypeRules() {
678
675
}
679
676
680
677
681
-
682
678
private Collection <? extends AccessRule > getTopmedRestrictedSubRules () {
683
679
Set <AccessRule > rules = new HashSet <AccessRule >();
684
680
rules .add (upsertTopmedRestrictedSubRule ("CATEGORICAL" , "$.query.query.variantInfoFilters[*].categoryVariantInfoFilters.*" ));
@@ -722,7 +718,6 @@ private AccessRule upsertTopmedRestrictedSubRule(String type, String rule) {
722
718
}
723
719
724
720
protected Collection <? extends AccessRule > getPhenotypeSubRules (String studyIdentifier , String conceptPath , String alias ) {
725
-
726
721
Set <AccessRule > rules = new HashSet <AccessRule >();
727
722
//categorical filters will always contain at least one entry (for the consent groups); it will never be empty
728
723
rules .add (createPhenotypeSubRule (fence_parent_consent_group_concept_path , "ALLOW_PARENT_CONSENT" , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "" , true ));
@@ -731,12 +726,16 @@ protected Collection<? extends AccessRule> getPhenotypeSubRules(String studyIden
731
726
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.fields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "FIELDS" , false ));
732
727
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "CATEGORICAL" , true ));
733
728
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.requiredFields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "REQ_FIELDS" , false ));
729
+ rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.anyRecordOf.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF" , false ));
730
+ rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.anyRecordOfMulti.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF_MULTI" , false ));
734
731
}
735
732
736
733
rules .add (createPhenotypeSubRule (conceptPath , alias + "_" + studyIdentifier , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "CATEGORICAL" , true ));
737
734
rules .add (createPhenotypeSubRule (conceptPath , alias + "_" + studyIdentifier , "$.query.query.numericFilters" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "NUMERIC" , true ));
738
735
rules .add (createPhenotypeSubRule (conceptPath , alias + "_" + studyIdentifier , "$.query.query.fields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "FIELDS" , false ));
739
736
rules .add (createPhenotypeSubRule (conceptPath , alias + "_" + studyIdentifier , "$.query.query.requiredFields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "REQUIRED_FIELDS" , false ));
737
+ rules .add (createPhenotypeSubRule (conceptPath , alias + "_" + studyIdentifier , "$.query.query.anyRecordOf.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF" , false ));
738
+ rules .add (createPhenotypeSubRule (conceptPath , alias + "_" + studyIdentifier , "$.query.query.anyRecordOfMulti.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF_MULTI" , false ));
740
739
741
740
return rules ;
742
741
}
@@ -759,12 +758,16 @@ private Collection<? extends AccessRule> getHarmonizedSubRules() {
759
758
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.fields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "FIELDS" , false ));
760
759
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "CATEGORICAL" , true ));
761
760
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.requiredFields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "REQ_FIELDS" , false ));
761
+ rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.anyRecordOf.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF" , false ));
762
+ rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.anyRecordOfMulti.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF_MULTI" , false ));
762
763
}
763
764
764
765
rules .add (createPhenotypeSubRule (fence_harmonized_concept_path , "HARMONIZED" , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "CATEGORICAL" , true ));
765
766
rules .add (createPhenotypeSubRule (fence_harmonized_concept_path , "HARMONIZED" , "$.query.query.numericFilters" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "NUMERIC" , true ));
766
767
rules .add (createPhenotypeSubRule (fence_harmonized_concept_path , "HARMONIZED" , "$.query.query.fields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "FIELDS" , false ));
767
768
rules .add (createPhenotypeSubRule (fence_harmonized_concept_path , "HARMONIZED" , "$.query.query.requiredFields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "REQUIRED_FIELDS" , false ));
769
+ rules .add (createPhenotypeSubRule (fence_harmonized_concept_path , "HARMONIZED" , "$.query.query.anyRecordOf.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF" , false ));
770
+ rules .add (createPhenotypeSubRule (fence_harmonized_concept_path , "HARMONIZED" , "$.query.query.anyRecordOfMulti.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF_MULTI" , false ));
768
771
769
772
return rules ;
770
773
}
@@ -784,6 +787,8 @@ protected Collection<? extends AccessRule> getPhenotypeRestrictedSubRules(String
784
787
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.fields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "FIELDS" , false ));
785
788
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.categoryFilters" , AccessRule .TypeNaming .ALL_CONTAINS , "CATEGORICAL" , true ));
786
789
rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.requiredFields.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "REQ_FIELDS" , false ));
790
+ rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.anyRecordOf.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF" , false ));
791
+ rules .add (createPhenotypeSubRule (underscorePath , "ALLOW " + underscorePath , "$.query.query.anyRecordOfMulti.[*]" , AccessRule .TypeNaming .ALL_CONTAINS_OR_EMPTY , "ANY_RECORD_OF_MULTI" , false ));
787
792
}
788
793
789
794
rules .add (createPhenotypeSubRule (null , alias + "_" + studyIdentifier + "_" + consentCode , "$.query.query.numericFilters.[*]" , AccessRule .TypeNaming .IS_EMPTY , "DISALLOW_NUMERIC" , false ));
@@ -817,11 +822,7 @@ protected AccessRule populateTopmedAccessRule(AccessRule rule, boolean includePa
817
822
rule .getGates ().addAll (getGates (includeParent , false , true ));
818
823
}
819
824
820
- if (rule .getSubAccessRule () == null ) {
821
- rule .setSubAccessRule (new HashSet <>(getAllowedQueryTypeRules ()));
822
- } else {
823
- rule .getSubAccessRule ().addAll (getAllowedQueryTypeRules ());
824
- }
825
+ addUniqueSubRules (rule , getAllowedQueryTypeRules ());
825
826
826
827
return rule ;
827
828
}
@@ -833,11 +834,9 @@ protected AccessRule populateHarmonizedAccessRule(AccessRule rule, String parent
833
834
)));
834
835
}
835
836
836
- if (rule .getSubAccessRule () == null ) {
837
- rule .setSubAccessRule (new HashSet <>(getAllowedQueryTypeRules ()));
838
- rule .getSubAccessRule ().addAll (getHarmonizedSubRules ());
839
- rule .getSubAccessRule ().addAll (getPhenotypeSubRules (studyIdentifier , parentConceptPath , projectAlias ));
840
- }
837
+ addUniqueSubRules (rule , getAllowedQueryTypeRules ());
838
+ addUniqueSubRules (rule , getHarmonizedSubRules ());
839
+ addUniqueSubRules (rule , getPhenotypeSubRules (studyIdentifier , parentConceptPath , projectAlias ));
841
840
842
841
return rule ;
843
842
}
@@ -918,7 +917,7 @@ protected AccessRule upsertTopmedAccessRule(String project_name, String consent_
918
917
919
918
String conceptPath = fence_topmed_consent_group_concept_path ;
920
919
// Check if the conceptPath has `\\\\` present. This technically represents `\\`.
921
- if (conceptPath != null && conceptPath .contains ("\\ \\ " )) {
920
+ if (conceptPath != null && conceptPath .contains ("\\ \\ " )) {
922
921
// This will convert all `\\\\` to `\\`.
923
922
conceptPath = conceptPath .replaceAll ("\\ \\ \\ \\ " , "\\ \\ " );
924
923
}
@@ -1001,8 +1000,8 @@ protected AccessRule createPhenotypeSubRule(String conceptPath, String alias, St
1001
1000
logger .debug ("createPhenotypeSubRule() Creating new access rule {}" , ar_name );
1002
1001
1003
1002
// Check if the conceptPath has `\\\\` present. This technically represents `\\`.
1004
- if (conceptPath != null && conceptPath .contains ("\\ \\ " )) {
1005
- // This will convert all `\\\\` to `\\`.
1003
+ if (conceptPath != null && conceptPath .contains ("\\ \\ " )) {
1004
+ // This will convert all `\\\\` to `\\`.
1006
1005
conceptPath = conceptPath .replaceAll ("\\ \\ \\ \\ " , "\\ \\ " );
1007
1006
}
1008
1007
@@ -1051,4 +1050,29 @@ private String escapePath(String path) {
1051
1050
public List <AccessRule > getAccessRulesByPrivilegeIds (List <UUID > privilegeIds ) {
1052
1051
return this .accessRuleRepo .getAccessRulesByPrivilegeIds (privilegeIds );
1053
1052
}
1053
+
1054
+ /**
1055
+ * Adds unique sub-rules to the provided parent access rule. This method ensures that duplicate sub-rules,
1056
+ * based on their names, are not added to the parent access rule.
1057
+ *
1058
+ * @param accessRule the parent access rule to which the sub-rules are added
1059
+ * @param subRulesToAdd the collection of sub-rules to be added to the parent access rule
1060
+ */
1061
+ private void addUniqueSubRules (AccessRule accessRule , Collection <? extends AccessRule > subRulesToAdd ) {
1062
+ if (accessRule .getSubAccessRule () == null ) {
1063
+ accessRule .setSubAccessRule (new HashSet <>());
1064
+ }
1065
+
1066
+ Set <String > existingRuleNames = accessRule .getSubAccessRule ().stream ()
1067
+ .map (AccessRule ::getName )
1068
+ .collect (Collectors .toSet ());
1069
+
1070
+ for (AccessRule subRule : subRulesToAdd ) {
1071
+ if (!existingRuleNames .contains (subRule .getName ())) {
1072
+ accessRule .getSubAccessRule ().add (subRule );
1073
+ existingRuleNames .add (subRule .getName ());
1074
+ }
1075
+ }
1076
+ }
1077
+
1054
1078
}
0 commit comments