1+ package de .triology .cas .authentication ;
2+
3+ import org .apereo .cas .authentication .handler .ByCredentialSourceAuthenticationHandlerResolver ;
4+ import org .apereo .cas .authentication .handler .DefaultAuthenticationHandlerResolver ;
5+ import org .apereo .cas .authentication .principal .PrincipalResolver ;
6+ import org .apereo .cas .util .CollectionUtils ;
7+ import org .apereo .cas .util .spring .beans .BeanSupplier ;
8+ import lombok .NonNull ;
9+ import lombok .extern .slf4j .Slf4j ;
10+ import lombok .val ;
11+ import org .apache .commons .lang3 .StringUtils ;
12+ import org .jooq .lambda .Unchecked ;
13+ import org .springframework .core .annotation .AnnotationAwareOrderComparator ;
14+ import java .util .LinkedHashMap ;
15+ import java .util .LinkedHashSet ;
16+ import java .util .Map ;
17+ import java .util .Set ;
18+ import java .util .stream .Collectors ;
19+ import org .apereo .cas .authentication .AuthenticationHandlerResolver ;
20+ import org .apereo .cas .authentication .DefaultAuthenticationEventExecutionPlan ;
21+ import org .apereo .cas .authentication .AuthenticationHandler ;
22+ import org .apereo .cas .authentication .AuthenticationTransaction ;
23+ import org .apereo .cas .authentication .MultifactorAuthenticationHandler ;
24+ import org .apereo .cas .authentication .AuthenticationException ;
25+
26+ import org .apereo .cas .multitenancy .TenantExtractor ;
27+
28+ @ Slf4j
29+ public class LegacyDefaultAuthenticationEventExecutionPlan extends DefaultAuthenticationEventExecutionPlan {
30+
31+ private final Map <AuthenticationHandler , PrincipalResolver > authenticationHandlerPrincipalResolverMap = new LinkedHashMap <>(0 );
32+
33+ public LegacyDefaultAuthenticationEventExecutionPlan (
34+ AuthenticationHandlerResolver defaultAuthenticationHandlerResolver , TenantExtractor tenantExtractor ) {
35+ super (defaultAuthenticationHandlerResolver , tenantExtractor );
36+ }
37+
38+ /**
39+ * Only override the handler resolution. Everything else stays as-is.
40+ */
41+ @ Override
42+ public @ NonNull Set <AuthenticationHandler > resolveAuthenticationHandlers (final AuthenticationTransaction transaction ) throws Throwable {
43+ // Use the public API of the parent
44+ val handlers = super .getAuthenticationHandlers ();
45+ LOGGER .debug ("Candidate/Registered authentication handlers for this transaction [{}] are [{}]" , transaction , handlers );
46+
47+ val handlerResolvers = super .getAuthenticationHandlerResolvers (transaction );
48+ LOGGER .debug ("Authentication handler resolvers for this transaction are [{}]" , handlerResolvers );
49+
50+ val resolvedHandlers = handlerResolvers .stream ()
51+ .filter (BeanSupplier ::isNotProxy )
52+ .filter (Unchecked .predicate (r -> r .supports (handlers , transaction )))
53+ .map (Unchecked .function (r -> r .resolve (handlers , transaction )))
54+ .flatMap (Set ::stream )
55+ .collect (Collectors .toCollection (LinkedHashSet ::new ));
56+
57+ // Fallback to a fresh DefaultAuthenticationHandlerResolver instance
58+ if (resolvedHandlers .isEmpty ()) {
59+ LOGGER .debug ("Resolvers produced no candidates. Using the default resolver fallback..." );
60+ var fallback = new DefaultAuthenticationHandlerResolver ();
61+ if (fallback .supports (handlers , transaction )) {
62+ resolvedHandlers .addAll (fallback .resolve (handlers , transaction ));
63+ }
64+ }
65+
66+ // Optional: filter by credential source, but *don’t* assume access to parent internals
67+ val byCredential = new ByCredentialSourceAuthenticationHandlerResolver ();
68+ if (byCredential .supports (resolvedHandlers , transaction )) {
69+ val credentialHandlers = byCredential .resolve (resolvedHandlers , transaction );
70+ if (!credentialHandlers .isEmpty ()) {
71+ LOGGER .debug ("Handlers resolved by credential source are [{}]" , credentialHandlers );
72+ resolvedHandlers .removeIf (handler ->
73+ !(handler instanceof MultifactorAuthenticationHandler )
74+ && credentialHandlers .stream ().noneMatch (credHandler ->
75+ StringUtils .equalsIgnoreCase (credHandler .getName (), handler .getName ())));
76+ }
77+ }
78+
79+ if (resolvedHandlers .isEmpty ()) {
80+ throw new AuthenticationException ("No authentication handlers could be resolved to support the authentication transaction" );
81+ }
82+ LOGGER .debug ("Resolved and finalized authentication handlers for this transaction are [{}]" , resolvedHandlers );
83+ return resolvedHandlers ;
84+ }
85+
86+ @ Override
87+ public Set <AuthenticationHandler > getAuthenticationHandlers () {
88+ val handlers = authenticationHandlerPrincipalResolverMap .keySet ().toArray (AuthenticationHandler []::new );
89+ AnnotationAwareOrderComparator .sortIfNecessary (handlers );
90+ return new LinkedHashSet <>(CollectionUtils .wrapList (handlers ));
91+ }
92+ }
0 commit comments