apereo/cas · warning

No security questions could be found for

Error message

No security questions could be found for [{}]

What it means

During password reset, the VerifyPasswordResetRequestAction fetches the user's security questions via PasswordManagementService.getSecurityQuestions(query). After canonicalization, if the returned map is empty it logs this warning and returns the error event, aborting the reset flow. It is thrown whenever security questions are enabled in cas.authn.pm.reset.security-questions-enabled but the backing password-management repository has no questions stored for that username.

Solutions

  1. Populate security questions (and answers) for the user in the backing password-management repository (e.g. the LDAP attribute or JDBC table configured under cas.authn.pm).
  2. Verify cas.authn.pm.reset.security-questions-enabled matches reality: set it to false if your deployment doesn't use security questions.
  3. Check the attribute/field mapping in PasswordManagementService configuration so getSecurityQuestions reads the correct attribute name.
  4. Check CAS logs at DEBUG/WARN for the underlying repository lookup to confirm the query reached the store and returned nothing rather than failing.

Example fix

// before (application.properties)
cas.authn.pm.reset.security-questions-enabled=true

// after: disable if questions are not provisioned
cas.authn.pm.reset.security-questions-enabled=false
Defensive patterns

Strategy: validation

Validate before calling

boolean hasSecurityQuestions = pm.getReset().isSecurityQuestionsEnabled()
    && FunctionUtils.doUnchecked(() -> !PasswordManagementService
        .canonicalizeSecurityQuestions(passwordManagementService.getSecurityQuestions(query)).isEmpty());

Try / catch

try {
    val questions = PasswordManagementService.canonicalizeSecurityQuestions(
        passwordManagementService.getSecurityQuestions(query));
    if (questions.isEmpty()) {
        return alternateResetFlow();
    }
} catch (Exception e) {
    LOGGER.warn("Security question lookup failed", e);
}

Prevention

When it happens

Trigger: User submits a password-reset request for an account whose security questions are not configured in the backing store (LDAP/JDBC/etc.); getSecurityQuestions(query) returns an empty map (or a map of null/empty values that canonicalization removes) while securityQuestionsEnabled=true.

Common situations: Admins enabled security questions in cas.properties but never populated the questions attribute in the user directory; user accounts provisioned without question/answer attributes; misconfigured attribute mapping so the question attribute name doesn't match; user typo'd their username and reset went to a valid but question-less account.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/038503b66054de30. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-pm-webflow/src/main/java/org/apereo/cas/pm/web/flow/actions/VerifyPasswordResetRequestAction.java:64

            transientTicket = resetRequest.getPasswordResetTicket().getId();
        }
        
        try {
            val ticketGrantingTicketId = WebUtils.getTicketGrantingTicketId(requestContext);
            if (StringUtils.isBlank(transientTicket) && StringUtils.isBlank(ticketGrantingTicketId)) {
                LOGGER.error("Password reset token is missing");
                return error();
            }
            resetRequest = getPasswordResetRequestFrom(requestContext, transientTicket)
                .orElseGet(() -> getPasswordResetRequestFrom(ticketGrantingTicketId));
            Objects.requireNonNull(resetRequest, "Password reset request cannot be found");
            
            val query = PasswordManagementQuery.builder().username(resetRequest.getUsername()).build();
            val pm = casProperties.getAuthn().getPm();
            if (pm.getReset().isSecurityQuestionsEnabled()) {
                val questions = FunctionUtils.doUnchecked(() -> PasswordManagementService.canonicalizeSecurityQuestions(passwordManagementService.getSecurityQuestions(query)));
                if (questions.isEmpty()) {
                    LOGGER.warn("No security questions could be found for [{}]", resetRequest);
                    return error();
                }
                PasswordManagementWebflowUtils.putPasswordResetSecurityQuestions(requestContext, questions);
            } else {
                LOGGER.debug("Security questions are not enabled for password management");
            }

            PasswordManagementWebflowUtils.putPasswordResetRequest(requestContext, resetRequest);
            PasswordManagementWebflowUtils.putPasswordResetUsername(requestContext, resetRequest.getUsername());
            PasswordManagementWebflowUtils.putPasswordResetSecurityQuestionsEnabled(requestContext, pm.getReset().isSecurityQuestionsEnabled());
            
            if (pm.getReset().isSecurityQuestionsEnabled()) {
                LOGGER.trace("Security questions are enabled; proceeding...");
                return success();
            }
            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_SECURITY_QUESTIONS_DISABLED);
        } catch (final Exception e) {
            LoggingUtils.error(LOGGER, "Password reset token could not be located or verified", e);

View on GitHub (pinned to e7288fc434)