55namespace SimpleSAML \OpenID \Federation \EntityCollection ;
66
77use SimpleSAML \OpenID \Codebooks \ClaimsEnum ;
8- use SimpleSAML \OpenID \Federation \EntityCollection ;
98use SimpleSAML \OpenID \Helpers ;
109
1110class EntityCollectionFilter
@@ -17,23 +16,35 @@ public function __construct(
1716
1817
1918 /**
19+ * Filters a list of entities based on the provided criteria.
20+ *
21+ * The method applies multiple filters in the following order:
22+ * 1. Filters entities by their type, based on the 'entity_type' criteria.
23+ * 2. Filters entities by their trust mark type, based on the
24+ * 'trust_mark_type' criteria.
25+ * 3. Filters entities by a textual query that checks multiple fields
26+ * (e.g., `display_name` or `organization_name`).
27+ *
28+ * @param array<string, array<string, mixed>> $entities The list of entities
29+ * to be filtered. Each entity is expected to be an associative array.
2030 * @param array{
21- * entity_type?: string[],
22- * trust_mark_type?: string,
23- * query?: string,
24- * trust_anchor?: string,
25- * } $criteria
26- * @return array<string, array<string, mixed>> Filtered
27- * entity payloads keyed by entity ID
31+ * entity_type?: string[],
32+ * trust_mark_type?: string[],
33+ * query?: string,
34+ * } $criteria The array of filtering criteria. It may contain:
35+ * - 'entity_type': An array of entity types to filter by.
36+ * - 'trust_mark_type': An array of trust mark types to filter by.
37+ * - 'query': A string used to perform a case-insensitive search on
38+ * specific fields.
39+ * @return array<string, array<string, mixed>> The filtered list of entities
40+ * that match all provided criteria.
2841 */
29- public function filter (EntityCollection $ entityCollection , array $ criteria ): array
42+ public function filter (array $ entities , array $ criteria ): array
3043 {
31- $ filtered = $ entityCollection ->all ();
32-
3344 // 1. entity_type
3445 if (isset ($ criteria ['entity_type ' ]) && $ criteria ['entity_type ' ] !== []) {
3546 $ types = $ criteria ['entity_type ' ];
36- $ filtered = array_filter ($ filtered , function (array $ payload ) use ($ types ): bool {
47+ $ entities = array_filter ($ entities , function (array $ payload ) use ($ types ): bool {
3748 $ metadata = $ payload [ClaimsEnum::Metadata->value ] ?? null ;
3849 if (!is_array ($ metadata )) {
3950 return false ;
@@ -50,26 +61,35 @@ public function filter(EntityCollection $entityCollection, array $criteria): arr
5061 }
5162
5263 // 2. trust_mark_type
53- if (isset ($ criteria ['trust_mark_type ' ])) {
54- $ tmType = $ criteria ['trust_mark_type ' ];
55- $ filtered = array_filter ($ filtered , function (array $ payload ) use ($ tmType ): bool {
56- $ marks = $ payload [ClaimsEnum::TrustMarks->value ] ?? null ;
57- if (is_array ($ marks )) {
58- foreach ($ marks as $ mark ) {
59- if (is_array ($ mark ) && ($ mark [ClaimsEnum::TrustMarkType->value ] ?? null ) === $ tmType ) {
60- return true ;
61- }
64+ if (isset ($ criteria ['trust_mark_type ' ]) && $ criteria ['trust_mark_type ' ] !== []) {
65+ $ criteriaTrustMarkTypes = $ criteria ['trust_mark_type ' ];
66+ $ entities = array_filter ($ entities , function (array $ payload ) use ($ criteriaTrustMarkTypes ): bool {
67+ $ entityTrustMarks = $ payload [ClaimsEnum::TrustMarks->value ] ?? null ;
68+ if (!is_array ($ entityTrustMarks )) {
69+ return false ;
70+ }
71+
72+ $ entityTrustMarkTypes = [];
73+ foreach ($ entityTrustMarks as $ mark ) {
74+ if (is_array ($ mark ) && isset ($ mark [ClaimsEnum::TrustMarkType->value ])) {
75+ $ entityTrustMarkTypes [] = $ mark [ClaimsEnum::TrustMarkType->value ];
6276 }
6377 }
6478
65- return false ;
79+ foreach ($ criteriaTrustMarkTypes as $ tmType ) {
80+ if (!in_array ($ tmType , $ entityTrustMarkTypes , true )) {
81+ return false ;
82+ }
83+ }
84+
85+ return true ;
6686 });
6787 }
6888
6989 // 3. query
7090 if (isset ($ criteria ['query ' ]) && $ criteria ['query ' ] !== '' ) {
7191 $ q = mb_strtolower ($ criteria ['query ' ]);
72- $ filtered = array_filter ($ filtered , function (array $ payload ) use ($ q ): bool {
92+ $ entities = array_filter ($ entities , function (array $ payload ) use ($ q ): bool {
7393 $ sub = is_string ($ payload [ClaimsEnum::Sub->value ] ?? null ) ?
7494 mb_strtolower ($ payload [ClaimsEnum::Sub->value ]) :
7595 '' ;
@@ -105,28 +125,6 @@ public function filter(EntityCollection $entityCollection, array $criteria): arr
105125 });
106126 }
107127
108- // 4. trust_anchor (simple prefix match for now as per spec suggestion,
109- // or more complex if needed). Historically, in some federation
110- // implementations, subordination is indicated via id prefix or
111- // specific claims. For this building block, we'll implement it as a
112- // filter on the authority hint if possible.
113- if (isset ($ criteria ['trust_anchor ' ])) {
114- $ ta = $ criteria ['trust_anchor ' ];
115- $ filtered = array_filter ($ filtered , function (array $ payload ) use ($ ta ): bool {
116- // In a top-down traversal, everything is subordinate to the TA we started with.
117- // If the collection contains multiple TAs, we would check authority_hints.
118- $ hints = $ this ->helpers ->arr ()->getNestedValue (
119- $ payload ,
120- ClaimsEnum::AuthorityHints->value ,
121- );
122- if (is_array ($ hints )) {
123- return in_array ($ ta , $ hints , true );
124- }
125-
126- return false ;
127- });
128- }
129-
130- return $ filtered ;
128+ return $ entities ;
131129 }
132130}
0 commit comments