{"record":{"id":"972ba5620c3b2f18","repo":"apereo/cas","slug":"password-does-not-match-value-on-record-972ba5","errorCode":null,"errorMessage":"Password does not match value on record.","messagePattern":"Password does not match value on record\\.","errorType":"exception","errorClass":"FailedLoginException","httpStatus":null,"severity":"error","filePath":"support/cas-server-support-jdbc-authentication/src/main/java/org/apereo/cas/jdbc/QueryDatabaseAuthenticationHandler.java","lineNumber":63,"sourceCode":"                + \", (especially if the query results do not contain the password field),\"\n                + \"and will instead only rely on a successful query execution with returned results in order to verify credentials\");\n        }\n    }\n\n    @Override\n    protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(\n        final UsernamePasswordCredential credential, final String originalPassword) throws Throwable {\n        val username = credential.getUsername();\n        val password = credential.toPassword();\n        try {\n            val dbFields = query(credential);\n            if (dbFields.containsKey(properties.getFieldPassword())) {\n                val dbPassword = (String) dbFields.get(properties.getFieldPassword());\n\n                val originalPasswordMatchFails = StringUtils.isNotBlank(originalPassword) && !matches(originalPassword, dbPassword);\n                val originalPasswordEquals = StringUtils.isBlank(originalPassword) && !Strings.CI.equals(password, dbPassword);\n                if (originalPasswordMatchFails || originalPasswordEquals) {\n                    throw new FailedLoginException(\"Password does not match value on record.\");\n                }\n            } else {\n                LOGGER.debug(\"Password field is not found in the query results. Checking for result count...\");\n                if (!dbFields.containsKey(\"total\")) {\n                    throw new FailedLoginException(\"Missing field 'total' from the query results for \" + username);\n                }\n\n                val count = dbFields.get(\"total\");\n                if (count == null || !NumberUtils.isCreatable(count.toString())) {\n                    throw new FailedLoginException(\"Missing field value 'total' from the query results for \"\n                        + username + \" or value not parseable as a number\");\n                }\n\n                val number = NumberUtils.createNumber(count.toString());\n                if (number.longValue() != 1) {\n                    throw new FailedLoginException(\"No records found for user \" + username);\n                }\n            }","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-jdbc-authentication/src/main/java/org/apereo/cas/jdbc/QueryDatabaseAuthenticationHandler.java#L45-L81","documentation":"QueryDatabaseAuthenticationHandler throws FailedLoginException('Password does not match value on record.') when the configured SQL returns a password column but the submitted password does not match it. If an 'original' (already-encoded) password property is set, that is compared via matches(); otherwise the raw password is compared case-insensitively against the stored value.","triggerScenarios":"dbFields contains properties.getFieldPassword() but either (a) originalPassword is non-blank and matches(originalPassword, dbPassword) is false, or (b) originalPassword is blank and the credential password is not case-insensitively equal to the stored value.","commonSituations":"Password stored hashed but compared as plaintext (or vice versa), wrong fieldPassword column configured, stored value includes whitespace/salt prefix, casing mismatch when DB stores mixed case and CI comparison still fails due to different algorithm output.","solutions":["Verify fieldPassword points at the real password column and that the storage format matches the comparison mode (set credentialToPasswordEncoder/credentialEncodingAlgorithm for hashed storage)","Check the sql only returns rows for the correct user so dbPassword is the right record","Trim/normalize stored values (no trailing spaces) or fix charset configuration","Test with a known-good user/password pair to isolate encoder vs data problems"],"exampleFix":"// before: DB stores SHA-256 hex, handler compares plaintext\n// cas.authn.jdbc.query[0].fieldPassword=password\n// after\n// cas.authn.jdbc.query[0].fieldPassword=password\n// cas.authn.jdbc.query[0].credentialEncodingAlgorithm=SHA-256","handlingStrategy":"validation","validationCode":"Map<String,Object> row = jdbc.queryForMap(sql, user);\nif (!row.containsKey(\"password\")) throw new IllegalStateException(\"fieldPassword column missing in result\");\nString stored = (String) row.get(\"password\");\n// verify comparison mode matches storage format\nboolean ok = stored.equals(digest(rawPassword, salt)) || stored.equalsIgnoreCase(rawPassword);","typeGuard":"boolean isPlausiblePassword(Object v) { return v instanceof String s && !s.isBlank(); }","tryCatchPattern":"try {\n    authResult = handler.authenticate(credential);\n} catch (FailedLoginException e) {\n    if (e.getMessage().contains(\"Password does not match\")) {\n        audit.logBadPassword(user); // wrong credentials; throttle and return generic error\n        throw new BadCredentialsException(\"Invalid credentials\");\n    }\n    throw e;\n}","preventionTips":["Match credentialEncodingAlgorithm/credentialToPasswordEncoder to the stored hash format","Ensure the sql returns exactly one row per user with the password column","Normalize stored values (no whitespace, consistent case/charset)","Smoke-test one known-good credential per environment"],"tags":["jdbc","authentication","password-compare"],"backgroundTag":"password-verification-failed","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"}