{"record":{"id":"dd00618338669365","repo":"apereo/cas","slug":"no-risk-calculators-are-available-to-evaluate-auth","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-electrofence/src/main/java/org/apereo/cas/impl/engine/DefaultAuthenticationRiskEvaluator.java","lineNumber":48,"sourceCode":"@Getter\n@RequiredArgsConstructor\n@Slf4j\n@Transactional(readOnly = true, value = CasEventRepository.TRANSACTION_MANAGER_EVENTS)\npublic class DefaultAuthenticationRiskEvaluator implements AuthenticationRiskEvaluator {\n    private final List<AuthenticationRequestRiskCalculator> calculators;\n    private final CasConfigurationProperties casProperties;\n    private final CasEventRepository casEventRepository;\n\n    @Audit(action = AuditableActions.EVALUATE_RISKY_AUTHENTICATION,\n        actionResolverName = AuditActionResolvers.ADAPTIVE_RISKY_AUTHENTICATION_ACTION_RESOLVER,\n        resourceResolverName = AuditResourceResolvers.ADAPTIVE_RISKY_AUTHENTICATION_RESOURCE_RESOLVER)\n    @Override\n    public AuthenticationRiskScore evaluate(final Authentication authentication,\n                                            final RegisteredService service,\n                                            final ClientInfo clientInfo) {\n\n        if (calculators.isEmpty()) {\n            LOGGER.warn(\"No risk calculators are available to evaluate authentication risk. \"\n                + \"CAS will proceed to regard the authentication attempt as highly risky. Examine your configuration \"\n                + \"and ensure at least one risk calculator is available and enabled to correctly assess authentication risk.\");\n            return AuthenticationRiskScore.highestRiskScore();\n        }\n\n        val scores = calculators\n            .stream()\n            .map(riskCalculator -> riskCalculator.calculate(authentication, service, clientInfo))\n            .filter(Objects::nonNull)\n            .toList();\n\n        LOGGER.debug(\"Collected [{}] risk scores from [{}] risk calculators\", scores.size(), calculators.size());\n        val sum = scores\n            .stream()\n            .map(AuthenticationRiskScore::getScore)\n            .filter(Objects::nonNull)\n            .reduce(BigDecimal.ZERO, BigDecimal::add);\n        val score = sum.divide(BigDecimal.valueOf(calculators.size()), 2, RoundingMode.UP);","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-electrofence/src/main/java/org/apereo/cas/impl/engine/DefaultAuthenticationRiskEvaluator.java#L30-L66","documentation":"DefaultAuthenticationRiskEvaluator.evaluate() requires at least one configured AuthenticationRiskCalculator to produce a risk score. When the calculators collection is empty it logs this warning and returns AuthenticationRiskScore.highestRiskScore(), meaning every authentication is treated as maximally risky — downstream risk response (usually MFA or blocking) will fire for all logins. This is a misconfiguration signal, not a runtime failure of the evaluator itself.","triggerScenarios":"The adaptive/risk feature is enabled (cas.authn.adaptive.risk.enabled=true) but no risk calculator bean (e.g. DefaultAuthenticationRequestRiskCalculator, DefaultAuthenticationDateTimeRiskCalculator, geo-location calculators) is registered or enabled in the application context.","commonSituations":"Enabling risk-based auth without enabling any of its component features (e.g. not enabling the IP-intelligence/geo modules that contribute calculators); a custom configuration that overrides the evaluator bean and forgets to inject calculators; module dependency missing so calculator auto-configuration never runs.","solutions":["Enable at least one risk calculator feature in cas.authn.adaptive.risk (e.g. request, dateTime, or geo calculators) and confirm its module is on the classpath.","Inspect the context for AuthenticationRiskCalculator beans; add a custom one if none exist.","If risk evaluation is not actually needed, disable cas.authn.adaptive.risk entirely so this evaluator is not engaged.","Review startup logs for the auto-configuration of the risk module to see why no calculators were created."],"exampleFix":"// before: risk enabled, no calculators\ncas.authn.adaptive.risk.enabled=true\n// after: enable at least one calculator source\ncas.authn.adaptive.risk.enabled=true\ncas.authn.adaptive.risk.request.enabled=true\ncas.authn.adaptive.risk.dateTime.enabled=true","handlingStrategy":"fallback","validationCode":"val calculators = applicationContext.getBeansOfType(AuthenticationRiskCalculator.class);\nif (calculators.isEmpty() && casProperties.getAuthn().getAdaptive().getRisk().isEnabled()) {\n    throw new IllegalStateException(\"Risk enabled but no AuthenticationRiskCalculator beans registered\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    val score = riskEvaluator.evaluate(authentication, service, clientInfo);\n} catch (Exception e) {\n    // fall back to a conservative-but-configured score\n    val score = AuthenticationRiskScore.defaultRiskScore();\n}","preventionTips":["Smoke-test the risk engine at startup: assert at least one calculator bean exists when risk is enabled.","Enable risk sub-features together with the risk module itself.","Write an integration test that runs evaluate() with the production configuration.","Pin CAS modules so calculator-contributing dependencies are not accidentally dropped from the overlay."],"tags":["risk-authentication","electrofence","misconfiguration","empty-collection"],"backgroundTag":"missing-dependency","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}