protected AuthenticationBuilder authenticateInternal(final AuthenticationTransaction transaction) throws Throwable {
        val credentials = transaction.getCredentials();
        LOGGER.debug("Authentication credentials provided for this transaction are [{}]", credentials);

        if (credentials.isEmpty()) {
            LOGGER.error("Resolved authentication handlers for this transaction are empty");
            throw new AuthenticationException("Resolved credentials for this transaction are empty");
        }

        val authenticationBuilder = new DefaultAuthenticationBuilder(NullPrincipal.getInstance());
        credentials.forEach(authenticationBuilder::addCredential);

        val handlerSet = authenticationEventExecutionPlan.resolveAuthenticationHandlers(transaction);
        LOGGER.debug("Candidate resolved authentication handlers for this transaction are [{}]", handlerSet);

        try {
            for (val credential : credentials) {
                LOGGER.debug("Attempting to authenticate credential [{}]", credential);

                val itHandlers = handlerSet.iterator();
                var proceedWithNextHandler = true;
                while (proceedWithNextHandler && itHandlers.hasNext()) {
                    val handler = itHandlers.next();
                    if (handler.supports(credential)) {
                        try {
                            val resolver = getPrincipalResolverLinkedToHandlerIfAny(handler, transaction);
                            LOGGER.debug("Attempting authentication of [{}] using [{}]", credential.getId(), handler.getName());
                            authenticateAndResolvePrincipal(authenticationBuilder, credential, resolver, handler, transaction.getService());

                            val authnResult = authenticationBuilder.build();
                            val executionResult = evaluateAuthenticationPolicies(authnResult, transaction, handlerSet);
                            proceedWithNextHandler = !executionResult.isSuccess();
                        } catch (final GeneralSecurityException e) {
                            handleAuthenticationException(e, handler.getName(), authenticationBuilder);
                            proceedWithNextHandler = shouldAuthenticationChainProceedOnFailure(transaction, e);
                        } catch (final Exception e) {
                            LOGGER.error("Authentication has failed. Credentials may be incorrect or CAS cannot "
                                + "find authentication handler that supports [{}] of type [{}]. Examine the configuration to "
                                + "ensure a method of authentication is defined and analyze CAS logs at DEBUG level to trace "
                                + "the authentication event.", credential, credential.getClass().getSimpleName());

                            handleAuthenticationException(e, handler.getName(), authenticationBuilder);
                            proceedWithNextHandler = shouldAuthenticationChainProceedOnFailure(transaction, e);
                        }
                    } else {
                        LOGGER.debug("Authentication handler [{}] does not support the credential type [{}].",
                            handler.getName(), credential);
                    }
                }
            }
            evaluateFinalAuthentication(authenticationBuilder, transaction, handlerSet);
            return authenticationBuilder;
        } finally {
            for (val handler : handlerSet) {
                if (handler.isDisposable() && handler instanceof final DisposableBean db) {
                    db.destroy();
                }
            }
        }
    }
This is {@link DefaultAuthenticationManager}, which provides common operations
around an authentication manager implementation.

@author Misagh Moayyed
@since 5.0.0
core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/DefaultAuthenticationManager.java