44
55namespace SimpleSAML \Module \oidc \Utils ;
66
7+ use SimpleSAML \Module \oidc \Codebooks \LimitsEnum ;
78use SimpleSAML \Module \oidc \ModuleConfig ;
89use SimpleSAML \Module \oidc \Services \LoggerService ;
910use SimpleSAML \OpenID \Exceptions \TrustMarkException ;
11+ use SimpleSAML \OpenID \Federation ;
12+ use SimpleSAML \OpenID \Federation \Claims \TrustMarksClaimBag ;
13+ use SimpleSAML \OpenID \Federation \EntityStatement ;
1014use SimpleSAML \OpenID \Federation \TrustChain ;
1115
1216class FederationParticipationValidator
1317{
1418 public function __construct (
1519 protected readonly ModuleConfig $ moduleConfig ,
20+ protected readonly Federation $ federation ,
1621 protected readonly LoggerService $ loggerService ,
1722 ) {
1823 }
@@ -26,34 +31,271 @@ public function __construct(
2631 */
2732 public function byTrustMarksFor (TrustChain $ trustChain ): void
2833 {
29- $ trustAnchor = $ trustChain ->getResolvedTrustAnchor ();
34+ $ leafEntityConfiguration = $ trustChain ->getResolvedLeaf ();
35+ $ trustAnchorEntityConfiguration = $ trustChain ->getResolvedTrustAnchor ();
36+
37+ $ this ->loggerService ->debug (
38+ sprintf (
39+ 'Validating federation participation by Trust Marks for leaf %s and Trust Anchor %s. ' ,
40+ $ leafEntityConfiguration ->getIssuer (),
41+ $ trustAnchorEntityConfiguration ->getIssuer (),
42+ ),
43+ );
3044
3145 $ trustMarkLimitsRules = $ this ->moduleConfig ->getTrustMarksNeededForFederationParticipationFor (
32- $ trustAnchor ->getIssuer (),
46+ $ trustAnchorEntityConfiguration ->getIssuer (),
3347 );
3448
3549 if (empty ($ trustMarkLimitsRules )) {
36- $ this ->loggerService ->debug ('No Trust Mark limits imposed for ' . $ trustAnchor ->getIssuer ());
50+ $ this ->loggerService ->debug (
51+ 'No Trust Mark limits imposed for ' . $ trustAnchorEntityConfiguration ->getIssuer (),
52+ );
3753 return ;
3854 }
3955
40- $ this ->loggerService ->debug ('Trust Mark limits for ' . $ trustAnchor ->getIssuer (), $ trustMarkLimitsRules );
56+ $ this ->loggerService ->debug (
57+ 'Trust Mark limits for ' . $ trustAnchorEntityConfiguration ->getIssuer (),
58+ $ trustMarkLimitsRules ,
59+ );
60+
61+
62+ /**
63+ * @var string $limitId
64+ * @var non-empty-string[] $limitedTrustMarkIds
65+ */
66+ foreach ($ trustMarkLimitsRules as $ limitId => $ limitedTrustMarkIds ) {
67+ $ limit = LimitsEnum::from ($ limitId );
4168
42- $ leaf = $ trustChain ->getResolvedLeaf ();
43- $ leafTrustMarks = $ leaf ->getTrustMarks ();
69+ if ($ limit === LimitsEnum::OneOf) {
70+ $ this ->validateTrustMarksClaimBagAsOneOfLimit (
71+ $ limitedTrustMarkIds ,
72+ $ leafEntityConfiguration ,
73+ $ trustAnchorEntityConfiguration ,
74+ );
75+ } else {
76+ $ this ->validateTrustMarksClaimBagAsAllOfLimit (
77+ $ limitedTrustMarkIds ,
78+ $ leafEntityConfiguration ,
79+ $ trustAnchorEntityConfiguration ,
80+ );
81+ }
82+ }
83+ }
84+
85+ /**
86+ * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException
87+ * @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
88+ * @throws \SimpleSAML\OpenID\Exceptions\JwsException
89+ * @throws \SimpleSAML\OpenID\Exceptions\TrustMarkException
90+ */
91+ protected function ensureTrustMarksClaimBag (EntityStatement $ leafEntityConfiguration ): TrustMarksClaimBag
92+ {
93+ $ leafTrustMarksClaimBag = $ leafEntityConfiguration ->getTrustMarks ();
4494
45- if (is_null ($ leafTrustMarks )) {
95+ if (is_null ($ leafTrustMarksClaimBag )) {
4696 $ error = sprintf (
4797 'Leaf entity %s does not have any Trust Marks available. ' ,
48- $ leaf ->getIssuer (),
98+ $ leafEntityConfiguration ->getIssuer (),
4999 );
50100
51- $ this ->loggerService ->error ($ error, compact ( ' trustMarkLimitsRules ' ) );
101+ $ this ->loggerService ->error ($ error );
52102 throw new TrustMarkException ($ error );
53103 }
54104
55- // Leaf has some Trust Marks.
105+ $ this ->loggerService ->debug (
106+ 'Leaf has Trust Marks available. ' ,
107+ ['leafTrustMarksClaimBag ' => $ leafTrustMarksClaimBag ->jsonSerialize ()],
108+ );
109+
110+ return $ leafTrustMarksClaimBag ;
111+ }
112+
113+ /**
114+ * @param non-empty-string[] $limitedTrustMarkIds
115+ * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException
116+ * @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
117+ * @throws \SimpleSAML\OpenID\Exceptions\JwsException
118+ * @throws \SimpleSAML\OpenID\Exceptions\TrustMarkException
119+ */
120+ public function validateTrustMarksClaimBagAsOneOfLimit (
121+ array $ limitedTrustMarkIds ,
122+ EntityStatement $ leafEntityConfiguration ,
123+ EntityStatement $ trustAnchorEntityConfiguration ,
124+ ): void {
125+ if (empty ($ limitedTrustMarkIds )) {
126+ $ this ->loggerService ->debug ('No Trust Mark limits given for OneOf limit rule, nothing to do. ' );
127+ return ;
128+ }
129+
130+ $ this ->loggerService ->debug (
131+ sprintf (
132+ 'Validating that entity %s has at least one valid Trust Mark for Trust Anchor %s. ' ,
133+ $ leafEntityConfiguration ->getIssuer (),
134+ $ trustAnchorEntityConfiguration ->getIssuer (),
135+ ),
136+ ['limitedTrustMarkIds ' => $ limitedTrustMarkIds ],
137+ );
138+
139+ $ trustMarksClaimBag = $ this ->ensureTrustMarksClaimBag ($ leafEntityConfiguration );
140+
141+ foreach ($ limitedTrustMarkIds as $ limitedTrustMarkId ) {
142+ $ trustMarksClaimValues = $ trustMarksClaimBag ->gerAllFor ($ limitedTrustMarkId );
143+ if (empty ($ trustMarksClaimValues )) {
144+ $ this ->loggerService ->debug (
145+ sprintf (
146+ 'There are no claims for Trust Mark ID %s. Trying next if available. ' ,
147+ $ limitedTrustMarkId ,
148+ ),
149+ );
150+ continue ;
151+ }
152+
153+ $ this ->loggerService ->debug (
154+ sprintf (
155+ 'There is/are %s claim/claims for Trust Mark ID %s. ' ,
156+ count ($ trustMarksClaimValues ),
157+ $ limitedTrustMarkId ,
158+ ),
159+ );
160+
161+ foreach ($ trustMarksClaimValues as $ idx => $ trustMarksClaimValue ) {
162+ $ this ->loggerService ->debug (
163+ sprintf (
164+ 'Validating claim %s for Trust Mark ID %s ' ,
165+ $ idx ,
166+ $ limitedTrustMarkId ,
167+ ),
168+ ['trustMarkClaim ' => $ trustMarksClaimValue ->jsonSerialize ()],
169+ );
170+
171+ try {
172+ $ this ->federation ->trustMarkValidator ()->forTrustMarksClaimValue (
173+ $ trustMarksClaimValue ,
174+ $ leafEntityConfiguration ,
175+ $ trustAnchorEntityConfiguration ,
176+ );
177+
178+ $ this ->loggerService ->debug (
179+ sprintf (
180+ 'Trust Mark ID %s validated using OneOf limit rule for entity %s for Trust Anchor %s. ' ,
181+ $ limitedTrustMarkId ,
182+ $ leafEntityConfiguration ->getIssuer (),
183+ $ trustAnchorEntityConfiguration ->getIssuer (),
184+ ),
185+ );
186+ return ;
187+ } catch (\Throwable $ exception ) {
188+ $ this ->loggerService ->debug (
189+ sprintf (
190+ 'Trust Mark ID %s validation failed with error: %s. Trying next if available. ' ,
191+ $ limitedTrustMarkId ,
192+ $ exception ->getMessage (),
193+ ),
194+ );
195+ continue ;
196+ }
197+ }
198+ }
199+
200+ $ error = sprintf (
201+ 'Leaf entity %s does not have any valid Trust Marks from the given list (%s). ' ,
202+ $ leafEntityConfiguration ->getIssuer (),
203+ implode (', ' , $ limitedTrustMarkIds ),
204+ );
205+
206+ $ this ->loggerService ->error ($ error );
207+ throw new TrustMarkException ($ error );
208+ }
209+
210+ /**
211+ * @param non-empty-string[] $limitedTrustMarkIds
212+ * @throws \SimpleSAML\OpenID\Exceptions\InvalidValueException
213+ * @throws \SimpleSAML\OpenID\Exceptions\EntityStatementException
214+ * @throws \SimpleSAML\OpenID\Exceptions\JwsException
215+ * @throws \SimpleSAML\OpenID\Exceptions\TrustMarkException
216+ */
217+ public function validateTrustMarksClaimBagAsAllOfLimit (
218+ array $ limitedTrustMarkIds ,
219+ EntityStatement $ leafEntityConfiguration ,
220+ EntityStatement $ trustAnchorEntityConfiguration ,
221+ ): void {
222+ if (empty ($ limitedTrustMarkIds )) {
223+ $ this ->loggerService ->debug ('No Trust Mark limits given for AllOf limit rule, nothing to do. ' );
224+ return ;
225+ }
226+
227+ $ this ->loggerService ->debug (
228+ sprintf (
229+ 'Validating that entity %s has all valid Trust Marks for Trust Anchor %s. ' ,
230+ $ leafEntityConfiguration ->getIssuer (),
231+ $ trustAnchorEntityConfiguration ->getIssuer (),
232+ ),
233+ ['limitedTrustMarkIds ' => $ limitedTrustMarkIds ],
234+ );
235+
236+ $ trustMarksClaimBag = $ this ->ensureTrustMarksClaimBag ($ leafEntityConfiguration );
237+
238+ foreach ($ limitedTrustMarkIds as $ limitedTrustMarkId ) {
239+ $ trustMarksClaimValues = $ trustMarksClaimBag ->gerAllFor ($ limitedTrustMarkId );
240+
241+ if (empty ($ trustMarksClaimValues )) {
242+ $ error = sprintf (
243+ 'There are no claims for Trust Mark ID %s. ' ,
244+ $ limitedTrustMarkId ,
245+ );
246+ $ this ->loggerService ->error ($ error );
247+ throw new TrustMarkException ($ error );
248+ }
56249
57- // TODO mivanci continue
250+ $ this ->loggerService ->debug (
251+ sprintf (
252+ 'There is/are %s claim/claims for Trust Mark ID %s. ' ,
253+ count ($ trustMarksClaimValues ),
254+ $ limitedTrustMarkId ,
255+ ),
256+ );
257+
258+ foreach ($ trustMarksClaimValues as $ idx => $ trustMarksClaimValue ) {
259+ $ this ->loggerService ->debug (
260+ sprintf (
261+ 'Validating claim %s for Trust Mark ID %s ' ,
262+ $ idx ,
263+ $ limitedTrustMarkId ,
264+ ),
265+ ['trustMarkClaim ' => $ trustMarksClaimValue ->jsonSerialize ()],
266+ );
267+
268+ try {
269+ $ this ->federation ->trustMarkValidator ()->forTrustMarksClaimValue (
270+ $ trustMarksClaimValue ,
271+ $ leafEntityConfiguration ,
272+ $ trustAnchorEntityConfiguration ,
273+ );
274+
275+ $ this ->loggerService ->debug (
276+ sprintf (
277+ 'Trust Mark ID %s validated. Trying next if available. ' ,
278+ $ limitedTrustMarkId ,
279+ ),
280+ );
281+ } catch (\Throwable $ exception ) {
282+ $ error = sprintf (
283+ 'Trust Mark ID %s validation failed with error: %s. ' ,
284+ $ limitedTrustMarkId ,
285+ $ exception ->getMessage (),
286+ );
287+ $ this ->loggerService ->error ($ error );
288+ throw new TrustMarkException ($ error );
289+ }
290+ }
291+ }
292+
293+ $ this ->loggerService ->debug (
294+ sprintf (
295+ 'Entity %s has all valid Trust Marks for Trust Anchor %s. ' ,
296+ $ leafEntityConfiguration ->getIssuer (),
297+ $ trustAnchorEntityConfiguration ->getIssuer (),
298+ ),
299+ );
58300 }
59301}
0 commit comments