{"record":{"id":"1415cc1d92a25efc","repo":"spring-projects/spring-security","slug":"saltgenerator-cannot-be-null","errorCode":null,"errorMessage":"saltGenerator cannot be null","messagePattern":"saltGenerator cannot be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java","lineNumber":72,"sourceCode":"\tprivate static final String SSHA_PREFIX = \"{SSHA}\";\n\n\tprivate static final String SSHA_PREFIX_LC = SSHA_PREFIX.toLowerCase(Locale.ENGLISH);\n\n\tprivate static final String SHA_PREFIX = \"{SHA}\";\n\n\tprivate static final String SHA_PREFIX_LC = SHA_PREFIX.toLowerCase(Locale.ENGLISH);\n\n\tprivate BytesKeyGenerator saltGenerator;\n\n\tprivate boolean forceLowerCasePrefix;\n\n\tpublic LdapShaPasswordEncoder() {\n\t\tthis(KeyGenerators.secureRandom());\n\t}\n\n\tpublic LdapShaPasswordEncoder(BytesKeyGenerator saltGenerator) {\n\t\tif (saltGenerator == null) {\n\t\t\tthrow new IllegalArgumentException(\"saltGenerator cannot be null\");\n\t\t}\n\t\tthis.saltGenerator = saltGenerator;\n\t}\n\n\tprivate byte[] combineHashAndSalt(byte[] hash, byte @Nullable [] salt) {\n\t\tif (salt == null) {\n\t\t\treturn hash;\n\t\t}\n\t\tbyte[] hashAndSalt = new byte[hash.length + salt.length];\n\t\tSystem.arraycopy(hash, 0, hashAndSalt, 0, hash.length);\n\t\tSystem.arraycopy(salt, 0, hashAndSalt, hash.length, salt.length);\n\t\treturn hashAndSalt;\n\t}\n\n\t/**\n\t * Calculates the hash of password (and salt bytes, if supplied) and returns a base64\n\t * encoded concatenation of the hash and salt, prefixed with {SHA} (or {SSHA} if salt\n\t * was used).","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/password/LdapShaPasswordEncoder.java#L54-L90","documentation":"The LdapShaPasswordEncoder(BytesKeyGenerator) constructor rejects a null saltGenerator with this IllegalArgumentException. The encoder needs a generator to produce random salt bytes for {SSHA} hashes (and salt comparison during matching), so a null generator would break both encode and matches. The no-arg constructor supplies KeyGenerators.secureRandom() automatically.","triggerScenarios":"Directly invoking new LdapShaPasswordEncoder(null), e.g. passing a field or injected dependency that failed to initialize.","commonSituations":"Spring wiring where a salt generator bean is absent so the constructor argument resolves to null; code paths that conditionally build the encoder and skip generator creation.","solutions":["Pass a real generator: new LdapShaPasswordEncoder(KeyGenerators.secureRandom()).","Use the no-argument constructor LdapShaPasswordEncoder() which defaults to a secure random generator.","Ensure any dependency-injected BytesKeyGenerator bean is actually defined and not null at construction time."],"exampleFix":"// before\nencoder = new LdapShaPasswordEncoder(saltGenerator); // null when bean missing\n// after\nencoder = new LdapShaPasswordEncoder(\n    saltGenerator != null ? saltGenerator : KeyGenerators.secureRandom());","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"BytesKeyGenerator safeGen = (gen != null) ? gen : KeyGenerators.secureRandom();\nLdapShaPasswordEncoder encoder = new LdapShaPasswordEncoder(safeGen);","tryCatchPattern":"try {\n    encoder = new LdapShaPasswordEncoder(saltGenerator);\n} catch (IllegalArgumentException e) {\n    encoder = new LdapShaPasswordEncoder(); // secureRandom default\n}","preventionTips":["Prefer the no-arg constructor unless you need a deterministic/custom generator (e.g. tests).","Ensure the BytesKeyGenerator bean exists before injection; use @Autowired(required=true) semantics or constructor validation."],"tags":["java","spring-security","ldap","null-check"],"backgroundTag":"null-argument","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}