/** * Creates a string representation of this password that is compatible with * Spring Security password encoders. * * @return The value of this object formatted as {Base64(salt)}password. */ public String format() { final StringBuilder result = new StringBuilder(); append(salt, result); result.append(password); return result.toString(); }
@Override public boolean matches(final String rawPassword, final JsonObject credentialsOnRecord) { try { final EncodedPassword encodedPassword = EncodedPassword.fromHonoSecret(credentialsOnRecord); final PasswordEncoder encoder = Optional.ofNullable(encoders.get(encodedPassword.hashFunction)).orElse(encoderForEncode); return encoder.matches(rawPassword, encodedPassword.format()); } catch (IllegalArgumentException e) { // invalid Base64 scheme LOG.debug("error matching password", e); return false; } }
/** * Creates an instance from the {Base64(salt)}password-hash formatted String. * * @param formattedPassword Password hash in the {Base64(salt)}password-hash format */ public EncodedPassword(final String formattedPassword) { parse(formattedPassword); }
/** * Verifies that a clear text password matches a given encoded password hash. * <p> * The password hash is expected to be of the form * <pre> * "{" Base64(salt) "}" passwordHash * </pre> * Where passwordHash is the Base64 encoding of the bytes resulting from applying * the hash function to the byte array consisting of the salt bytes and the UTF-8 * encoding of the clear text password. * * @param rawPassword Password to verify in plain text * @param encodedPassword Encoded password on the record in {Base64(salt)}passwordHash format * @return {@code true} if encoded password hash matches the one on record, {@code false} otherwise * @throws IllegalArgumentException if the encodedPassword does not contain valid Base64 schema. */ @Override public boolean matches(final CharSequence rawPassword, final String encodedPassword) { final EncodedPassword password = new EncodedPassword(encodedPassword); final byte[] digested = digest(password.salt, rawPassword.toString()); final byte[] pwdHash = Base64.getDecoder().decode(password.password); return Arrays.equals(digested, pwdHash); }
@Override public JsonObject encode(final String rawPassword) { final EncodedPassword encodedPwd = new EncodedPassword(encoderForEncode.encode(rawPassword)); return CredentialsObject.hashedPasswordSecretForPasswordHash( encodedPwd.password, idForEncode, null, null, encodedPwd.salt); }
/** * Creates a new instance from Hono Secret. * <p> * The secret is expected to be of type <em>hashed-password</em> as defined by * <a href="https://www.eclipse.org/hono/api/credentials-api/#hashed-password">Hono's Credentials API</a>. * * @param secret JSON object that contains the Hono-formatted secret. * @return The password value object. * @throws NullPointerException if secret is {@code null}. * @throws IllegalArgumentException if the secret does not contain a password hash * or if the salt is not valid Base64 schema. */ public static EncodedPassword fromHonoSecret(final JsonObject secret) throws IllegalArgumentException { Objects.requireNonNull(secret); final String pwdHash = CredentialsConstants.getPasswordHash(secret); if (pwdHash == null) { throw new IllegalArgumentException("hashed-password secret does not contain a pwd hash"); } final String hashFunction = CredentialsConstants.getHashFunction(secret); final String encodedSalt = CredentialsConstants.getPasswordSalt(secret); final EncodedPassword encodedPassword = new EncodedPassword(); encodedPassword.hashFunction = hashFunction; encodedPassword.password = pwdHash; if (encodedSalt != null) { encodedPassword.salt = Base64.getDecoder().decode(encodedSalt); } return encodedPassword; }