@Audit(action = AuditableActions.EVALUATE_RISKY_AUTHENTICATION,
        actionResolverName = AuditActionResolvers.ADAPTIVE_RISKY_AUTHENTICATION_ACTION_RESOLVER,
        resourceResolverName = AuditResourceResolvers.ADAPTIVE_RISKY_AUTHENTICATION_RESOURCE_RESOLVER)
    @Override
    public AuthenticationRiskScore evaluate(final Authentication authentication,
                                            final RegisteredService service,
                                            final ClientInfo clientInfo) {

        if (calculators.isEmpty()) {
            LOGGER.warn("No risk calculators are available to evaluate authentication risk. "
                + "CAS will proceed to regard the authentication attempt as highly risky. Examine your configuration "
                + "and ensure at least one risk calculator is available and enabled to correctly assess authentication risk.");
            return AuthenticationRiskScore.highestRiskScore();
        }

        val scores = calculators
            .stream()
            .map(riskCalculator -> riskCalculator.calculate(authentication, service, clientInfo))
            .filter(Objects::nonNull)
            .toList();

        LOGGER.debug("Collected [{}] risk scores from [{}] risk calculators", scores.size(), calculators.size());
        val sum = scores
            .stream()
            .map(AuthenticationRiskScore::getScore)
            .filter(Objects::nonNull)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        val score = sum.divide(BigDecimal.valueOf(calculators.size()), 2, RoundingMode.UP);
        LOGGER.debug("Final authentication risk score is calculated as [{}]", score);
        return new AuthenticationRiskScore(score).withClientInfo(clientInfo);
    }
This is {@link DefaultAuthenticationRiskEvaluator}.

@author Misagh Moayyed
@since 5.1.0
support/cas-server-support-electrofence/src/main/java/org/apereo/cas/impl/engine/DefaultAuthenticationRiskEvaluator.java