3131import static org .assertj .core .api .Assertions .assertThat ;
3232import static org .assertj .core .api .Assertions .assertThatIllegalArgumentException ;
3333import static org .assertj .core .api .Assertions .assertThatIllegalStateException ;
34+ import static org .assertj .core .api .InstanceOfAssertFactories .type ;
3435
3536/**
3637 * Test {@link AllRequiredFactorsAuthorizationManager}.
3738 *
3839 * @author Rob Winch
40+ * @author Evgeniy Cheban
3941 * @since 7.0
4042 */
4143class AllRequiredFactorsAuthorizationManagerTests {
@@ -51,6 +53,15 @@ class AllRequiredFactorsAuthorizationManagerTests {
5153 .validDuration (Duration .ofHours (1 ))
5254 .build ();
5355
56+ private static final RequiredFactor REQUIRED_OTT = RequiredFactor
57+ .withAuthority (FactorGrantedAuthority .OTT_AUTHORITY )
58+ .build ();
59+
60+ private static final RequiredFactor EXPIRING_OTT = RequiredFactor
61+ .withAuthority (FactorGrantedAuthority .OTT_AUTHORITY )
62+ .validDuration (Duration .ofHours (1 ))
63+ .build ();
64+
5465 @ Test
5566 void authorizeWhenGranted () {
5667 AllRequiredFactorsAuthorizationManager <Object > allFactors = AllRequiredFactorsAuthorizationManager .builder ()
@@ -219,6 +230,105 @@ void authorizeWhenDifferentFactorGrantedAuthorityThenMissing() {
219230 assertThat (result .getFactorErrors ()).containsExactly (RequiredFactorError .createMissing (REQUIRED_PASSWORD ));
220231 }
221232
233+ @ Test
234+ void anyOfWhenOneGrantedThenGranted () {
235+ AllRequiredFactorsAuthorizationManager <Object > expiringPasswordAndOtt = AllRequiredFactorsAuthorizationManager
236+ .builder ()
237+ .requireFactor (EXPIRING_PASSWORD )
238+ .requireFactor (EXPIRING_OTT )
239+ .build ();
240+ AllRequiredFactorsAuthorizationManager <Object > passwordAndExpiringOtt = AllRequiredFactorsAuthorizationManager
241+ .builder ()
242+ .requireFactor (REQUIRED_PASSWORD )
243+ .requireFactor (EXPIRING_OTT )
244+ .build ();
245+ FactorGrantedAuthority passwordFactor = FactorGrantedAuthority .withAuthority (EXPIRING_PASSWORD .getAuthority ())
246+ .issuedAt (Instant .now ().minus (Duration .ofHours (2 )))
247+ .build ();
248+ FactorGrantedAuthority ottFactor = FactorGrantedAuthority .withAuthority (EXPIRING_OTT .getAuthority ()).build ();
249+ AuthorizationManager <Object > anyOf = AllRequiredFactorsAuthorizationManager .anyOf (expiringPasswordAndOtt ,
250+ passwordAndExpiringOtt );
251+ Authentication authentication = new TestingAuthenticationToken ("user" , "password" , passwordFactor , ottFactor );
252+ AuthorizationResult result = anyOf .authorize (() -> authentication , DOES_NOT_MATTER );
253+ assertThat (result ).isNotNull ();
254+ assertThat (result .isGranted ()).isTrue ();
255+ }
256+
257+ @ Test
258+ void anyOfWhenSameAuthorityDifferentValidDurationThenBothErrorsReturned () {
259+ AllRequiredFactorsAuthorizationManager <Object > passwordAndOtt = AllRequiredFactorsAuthorizationManager .builder ()
260+ .requireFactor (REQUIRED_PASSWORD )
261+ .requireFactor (REQUIRED_OTT )
262+ .build ();
263+ AllRequiredFactorsAuthorizationManager <Object > passwordAndExpiringOtt = AllRequiredFactorsAuthorizationManager
264+ .builder ()
265+ .requireFactor (REQUIRED_PASSWORD )
266+ .requireFactor (EXPIRING_OTT )
267+ .build ();
268+ FactorGrantedAuthority passwordFactor = FactorGrantedAuthority .withAuthority (REQUIRED_PASSWORD .getAuthority ())
269+ .build ();
270+ AuthorizationManager <Object > anyOf = AllRequiredFactorsAuthorizationManager .anyOf (passwordAndOtt ,
271+ passwordAndExpiringOtt );
272+ Authentication authentication = new TestingAuthenticationToken ("user" , "password" , passwordFactor );
273+ AuthorizationResult result = anyOf .authorize (() -> authentication , DOES_NOT_MATTER );
274+ assertThat (result ).asInstanceOf (type (FactorAuthorizationDecision .class )).satisfies ((decision ) -> {
275+ assertThat (decision .isGranted ()).isFalse ();
276+ assertThat (decision .getFactorErrors ()).containsExactly (RequiredFactorError .createMissing (REQUIRED_OTT ),
277+ RequiredFactorError .createMissing (EXPIRING_OTT ));
278+ });
279+ }
280+
281+ @ Test
282+ void anyOfWhenIdenticalErrorInMultipleManagersThenDeduplicated () {
283+ AllRequiredFactorsAuthorizationManager <Object > passwordAndOtt = AllRequiredFactorsAuthorizationManager .builder ()
284+ .requireFactor (REQUIRED_PASSWORD )
285+ .requireFactor (REQUIRED_OTT )
286+ .build ();
287+ AllRequiredFactorsAuthorizationManager <Object > passwordOnly = AllRequiredFactorsAuthorizationManager .builder ()
288+ .requireFactor (REQUIRED_PASSWORD )
289+ .build ();
290+ AuthorizationManager <Object > anyOf = AllRequiredFactorsAuthorizationManager .anyOf (passwordAndOtt , passwordOnly );
291+ Authentication authentication = new TestingAuthenticationToken ("user" , "password" , "ROLE_USER" );
292+ AuthorizationResult result = anyOf .authorize (() -> authentication , DOES_NOT_MATTER );
293+ assertThat (result ).asInstanceOf (type (FactorAuthorizationDecision .class )).satisfies ((decision ) -> {
294+ assertThat (decision .isGranted ()).isFalse ();
295+ assertThat (decision .getFactorErrors ()).containsOnly (RequiredFactorError .createMissing (REQUIRED_PASSWORD ),
296+ RequiredFactorError .createMissing (REQUIRED_OTT ));
297+ });
298+ }
299+
300+ @ Test
301+ void anyOfWhenDeniedThenErrorsRetainedInManagerOrder () {
302+ AllRequiredFactorsAuthorizationManager <Object > passwordOnly = AllRequiredFactorsAuthorizationManager .builder ()
303+ .requireFactor (REQUIRED_PASSWORD )
304+ .build ();
305+ AllRequiredFactorsAuthorizationManager <Object > ottOnly = AllRequiredFactorsAuthorizationManager .builder ()
306+ .requireFactor (REQUIRED_OTT )
307+ .build ();
308+ AuthorizationManager <Object > anyOf = AllRequiredFactorsAuthorizationManager .anyOf (passwordOnly , ottOnly );
309+ Authentication authentication = new TestingAuthenticationToken ("user" , "password" , "ROLE_USER" );
310+ AuthorizationResult result = anyOf .authorize (() -> authentication , DOES_NOT_MATTER );
311+ assertThat (result ).asInstanceOf (type (FactorAuthorizationDecision .class )).satisfies ((decision ) -> {
312+ assertThat (decision .isGranted ()).isFalse ();
313+ assertThat (decision .getFactorErrors ()).containsExactly (RequiredFactorError .createMissing (REQUIRED_PASSWORD ),
314+ RequiredFactorError .createMissing (REQUIRED_OTT ));
315+ });
316+ }
317+
318+ @ Test
319+ void anyOfWhenEmptyManagersThenIllegalArgumentException () {
320+ assertThatIllegalArgumentException ().isThrownBy (() -> AllRequiredFactorsAuthorizationManager .anyOf ());
321+ }
322+
323+ @ Test
324+ void anyOfWhenSingleManagerThenReturnsSameInstance () {
325+ AllRequiredFactorsAuthorizationManager <Object > manager = AllRequiredFactorsAuthorizationManager .builder ()
326+ .requireFactor (REQUIRED_PASSWORD )
327+ .build ();
328+ AuthorizationManager <Object > result = AllRequiredFactorsAuthorizationManager .anyOf (manager );
329+ assertThat (result == manager ).isTrue ();
330+ }
331+
222332 @ Test
223333 void setClockWhenNullThenIllegalArgumentException () {
224334 AllRequiredFactorsAuthorizationManager <Object > allFactors = AllRequiredFactorsAuthorizationManager .builder ()
0 commit comments