{"record":{"id":"507668b091db1755","repo":"apereo/cas","slug":"encoded-password-is-null","errorCode":null,"errorMessage":"Encoded password is null.","messagePattern":"Encoded password is null\\.","errorType":"exception","errorClass":"AccountNotFoundException","httpStatus":null,"severity":"error","filePath":"core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/handler/support/AbstractUsernamePasswordAuthenticationHandler.java","lineNumber":88,"sourceCode":"    @Override\n    protected AuthenticationHandlerExecutionResult doAuthentication(final Credential credential, final Service service) throws Throwable {\n        val originalUserPass = (UsernamePasswordCredential) credential;\n        val userPass = new UsernamePasswordCredential();\n        FunctionUtils.doUnchecked(_ -> BeanUtils.copyProperties(userPass, originalUserPass));\n        transformUsername(userPass);\n        transformPassword(userPass);\n        LOGGER.debug(\"Attempting authentication internally for transformed credential [{}]\", userPass);\n        return authenticateUsernamePasswordInternal(userPass, originalUserPass.toPassword());\n    }\n\n    protected void transformPassword(final UsernamePasswordCredential userPass) throws FailedLoginException, AccountNotFoundException {\n        if (StringUtils.isBlank(userPass.toPassword())) {\n            throw new FailedLoginException(\"Password is null.\");\n        }\n        LOGGER.debug(\"Attempting to encode credential password via [{}] for [{}]\", passwordEncoder.getClass().getName(), userPass.getUsername());\n        val transformedPsw = passwordEncoder.encode(userPass.toPassword());\n        if (StringUtils.isBlank(transformedPsw)) {\n            throw new AccountNotFoundException(\"Encoded password is null.\");\n        }\n        userPass.assignPassword(transformedPsw);\n    }\n    \n    /**\n     * Authenticates a username/password credential by an arbitrary strategy with extra parameter original credential password before\n     * encoding password. Override it if implementation need to use original password for authentication.\n     *\n     * @param credential       the credential object bearing the transformed username and password.\n     * @param originalPassword original password from credential before password encoding\n     * @return AuthenticationHandlerExecutionResult resolved from credential on authentication success or null if no principal could be resolved from the credential.\n     * @throws Throwable the throwable\n     */\n    protected abstract AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(\n        UsernamePasswordCredential credential,\n        @Nullable String originalPassword) throws Throwable;\n\n    /**","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/handler/support/AbstractUsernamePasswordAuthenticationHandler.java#L70-L106","documentation":"transformPassword throws AccountNotFoundException when the configured PasswordEncoder encodes the password into a null/empty string. The raw password existed, but the encoding step produced nothing, so CAS reports the account as not found rather than continuing with an unusable encoded value.","triggerScenarios":"transformPassword calls passwordEncoder.encode(userPass.toPassword()) and the result is blank — e.g. a custom PasswordEncoder whose encode() returns null, a Groovy/scripted encoder that fails silently, or an encoder misconfigured with an empty format.","commonSituations":"Custom PasswordEncoder implementation bug (returning null on certain inputs); scripted encoder throwing internally and being swallowed; char array-to-string conversion wiping the value; encoder bean wired to the wrong implementation after a config refactor.","solutions":["Inspect the configured PasswordEncoder; ensure its encode() never returns null/empty — return the input or throw a clear error instead.","Test the encoder directly in a unit test with the same password value.","If using a Groovy/scripted encoder, add explicit return statements and logging inside the script.","Verify the encoder bean binding on the handler (passwordEncoder field) points to the intended implementation.","Check for character-encoding/array-conversion issues in custom encoder code."],"exampleFix":"// before\npublic String encode(CharSequence raw) {\n    try { return sha256(raw); } catch (Exception e) { return null; }\n}\n// after\npublic String encode(CharSequence raw) {\n    try { return sha256(raw); } catch (Exception e) { throw new IllegalStateException(\"password encoding failed\", e); }\n}","handlingStrategy":"validation","validationCode":"// verify your encoder before wiring it\nPasswordEncoder enc = ...;\nString encoded = enc.encode(\"sample-password\");\nif (StringUtils.isBlank(encoded)) { throw new IllegalStateException(\"PasswordEncoder must never return a blank value\"); }","typeGuard":null,"tryCatchPattern":"try {\n    return handler.authenticate(credential, service);\n} catch (AccountNotFoundException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Encoded password\")) {\n        LOGGER.error(\"PasswordEncoder returned a blank value; fix or replace the encoder\", e);\n    }\n    throw new BadCredentialsAuthenticationException();\n}","preventionTips":["Unit test custom/scripted PasswordEncoders for null/empty return paths.","Throw a descriptive exception from encode() rather than returning null on internal failure.","Pin and review the encoder bean assignment after configuration refactors."],"tags":["authentication","password-encoding","encoder"],"backgroundTag":"unexpected-empty-value","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"}