I was suprised to see that the Spring Security PasswordEncoder (the implementation I use is BCryptPasswordEncoder if this makes a difference) generates a salt when encoding passwords.
What I don't get is, how am I supposed to obtain this salt when validating login requests? I meant to use my own salt, but (presumably) because of the automatic salt generation, I get different hash values for the same password+salt combination.
I'm a bit confused, and don't know how the encoder should be used properly.
You should be using the builtin validation logic, not writing your own password validation functions. Hence you shouldn't need to obtain the salt that Spring Security generates. See the documentation in PasswordEncoder:
/**
* Verify the encoded password obtained from storage matches the submitted raw
* password after it too is encoded. Returns true if the passwords match, false if
* they do not. The stored password itself is never decoded.
*
* #param rawPassword the raw password to encode and match
* #param encodedPassword the encoded password from storage to compare with
* #return true if the raw password, after encoding, matches the encoded password from
* storage
*/
boolean matches(CharSequence rawPassword, String encodedPassword);
Related
I'm trying to update a field of my user DTO, but every time I update by doing userService.save(user), my login credentials become invalid in the database, because when I first get the user I get the encrypted password in the password field of my DTO, and when I save the user again I'm re-encrypting the encrypted password making the password different than before.
How can I go about fixing this? Should I decrypt the password when I first query the database in my user service? Is that safe?
Edit : found out you can't decode the password (I'm using BCryptPasswordEncoder) anyways. Is there a way to update all my fields without affecting the password?
Have you tried to update only the column without saving the entire entity?
There is an example of how to create such a query in the Spring Data JPA documentation:
https://docs.spring.io/spring-data/jpa/docs/2.1.1.RELEASE/reference/html/#jpa.modifying-queries
Addition:
If there is a way to save only the password without re-encrypting it? If so, you could perhaps try to:
- Obtain the encrypted password.
- Update the user entity (resulting in the encrypted password being encrypted a second time).
- Overwrite only the password in the user with the encrypted password obtained in step 1.
You should use entity listeners.
Look here https://www.concretepage.com/java/jpa/jpa-entitylisteners-example-with-callbacks-prepersist-postpersist-postload-preupdate-postupdate-preremove-postremove
Create entity listener class, implement preUpdate method.
You should inject applicationContext into class. You can find bean "passwordEncoder". Spring use it to encode password.
In pre update method you get your raw password, create encoded version like
passwordEncoder.encode(password) and set it back to the entity.
This question already has answers here:
Getting same hashed value while using BCryptPasswordEncoder
(2 answers)
Closed 7 years ago.
How to compare password entered by user and saved in DB using BCryptPasswordEncoder.
Below is the code we are using to save password in DB:
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String password = encoder.encode("Test"));
DB.save(password);
How to check user entered password and above saved password to allow login?
Any suggestions or links which explains above procedure will be of great help?
Assuming your encoding method will give the same value each time you encode a given string, then:
Look up the user by username.
Encode the password they typed in, store in memory.
Check the encoded value with the value in the Database. If it matches, then they typed the right password. If it doesn't match, then they didn't.
I would like to use Android's built-in AccountManager to handle accounts for our native Android app. However, we have a peculiar need.
It appears that Android's concept of an Account is a combination of name (i.e. MazerRackham#example.com) and type (i.e. com.example). Name is the username you login with. Type is associated with your application or company.
However, our REST backend allows a single user to have multiple accounts and each account must be accessed by its own unique hash tied to the combination of one username and one account number (in addition to type).
I already have the AccountAuthenticator, AuthenticationService, and AccountAuthenticatorActivity working for a single user with a single account number and single stored hash. Is there any way in which I could implement my AccountAuthenticator to handle users with multiple accounts under the same username, each requiring a hash? Would it be possible to attach a delimiter to the username and split it into username and account number every time I use it?
If I cannot figure out a way to handle this, how should I gracefully fall back during AbstractAccountAuthenticator.getAuthToken? Would it make sense to set the hash to a special flag value and use legacy login methods for that user? Or is that too much of a hack?
Thanks for your help!
If you don't mind the hash being public, you can certainly make the account name username|hash (or whatever separator you want) - the system does not care what you use for an account name except that it uniquely defines a user.
I ended up serializing the data into the username using an at sign (#) as a delimiter. I chose the at sign because it's the only restricted character in an e-mail address that should only be used exactly one time.
Here is the code from getAuthToken in my AccountAuthenticator which gets called only if I need to obtain a fresh token for that user and account id:
/*
*
* The login params need to handle users with multiple accounts under the same username.
*
* Since Android's AccountManager does not allow multiple accounts per username, I had
* to create a hack which joins and splits the username on a delimiter to serialize the
* data and retrieve the account number for users with multiple accounts. I chose the #
* sign as a delimiter because e-mail addresses have VERY few invalid characters in
* the account name part of the address.
*
* If the user has multiple accounts, we need to create each one in AccountManager.
*
* */
String[] accountParts = account.name.split("#");
numParts = accountParts.length;
if (numParts<2) {
Log.wtf(Config.TAG, "Username split produced too few parts. WTF.");
return null;
}
String email = accountParts[0] + "#" + accountParts[1];
if (numParts==3) {
String account_id = accountParts[2];
} else if (numParts>3) {
Log.wtf(Config.TAG, "Username split produced too many parts. WTF.");
return null;
}
I have a simple setup with an app server backed on to CouchDB in which I'm using CouchDB's built-in user authentication for users of the app server. The app server can access the _users database and retrieve a user's doc.
I am trying to replicate the password hash function so I can validate a user's password in the app server without having to authenticate against CouchDB.
The CouchDB security spec states:
The "password_sha" attribute is an hexadecimal representation of the SHA-1 hash computed over a string that matches the user password concatenated with a salt (ideally a random string). The salt attribute is the hexadecimal representation of the salt used to generate the user's password hash.
Since CouchDB 1.2.0, the password_sha and salt fields are automatically created when a password field is present in the user document. When the user document is written, CouchDB checks for the existence of the password field and if it exists, it will generate a salt, hash the value of the password field and hash the concatenation of the password hash and the salt. It then writes the resulting password into the password_sha field and the salt into the salt field. The password` field is removed.
Relevant source code:
% Lines 72-74 of couch_httpd_auth.erl
UserSalt = couch_util:get_value(<<"salt">>, UserProps, <<>>),
PasswordHash = hash_password(?l2b(Pass), UserSalt),
ExpectedHash = couch_util:get_value(<<"password_sha">>, UserProps, nil),
% Lines 237-238 of couch_httpd_auth.erl
hash_password(Password, Salt) ->
?l2b(couch_util:to_hex(crypto:sha(<<Password/binary, Salt/binary>>))).
This is my attempt to replicate it with a test user that has a password of "password":
import java.security.MessageDigest
import org.apache.commons.codec.binary.Hex
import org.specs2.mutable.Specification
class PasswordSpec extends Specification {
"Password" should {
"match" in {
val password = "password"
val hexEncodedPasswordHash = "0fed560a9928b50761ebec5aa97c815999e6def0"
val hexEncodedSalt = "2ba345d5f2880fae25de9ec7a78d38ae"
val charset = "UTF-8"
val codec = new Hex(charset)
val md = MessageDigest.getInstance("SHA-1")
md.reset()
md.update(password.getBytes(charset))
md.update(codec.decode(hexEncodedSalt.getBytes(charset)))
val hashBytes = md.digest()
val hexEncodedHash = new String(codec.encode(hashBytes), charset)
hexEncodedHash mustEqual(hexEncodedPasswordHash)
}
}
}
This test is failing and I've run out of ideas as to why.
I figured it out. The salt bytes do not need to be decoded from hex before being concatenated with the password bytes.
In my web app which uses servlets and hibernate. I need to authenticate a Customer who enters a password.
If he is already in database, I need to check if his password matches that of the record in db.For a new Customer, I want to take a password and create a record for him.
I tried to do it this way for the scenarios.
Existing Customer enters an emailAddress and password
String email = req.getParameter("emailAddress");
String password = req.getParameter("password");
Customer cust = dao.findByEmailAddress(email);
Now, how do I check if this cust object is associated with a password and that matches what the user entered? Manning's hibernate book example stores password as a String in Customer class. Is this a good idea? How will this be stored in database?
When using hibernate, how can this be handled? I have heard people mentioning about storing passwords as hash. But I am not very sure how I can do this in my app.
Can someone tell me how I can tackle this?
Storing plain text passwords is never a good idea. In fact it is listed as #8 threat in the Top 25 Most Dangerous Software Errors.
You need to encrypt the passwords before writing them in the database. When searching for a user use the encrypted password
String email = req.getParameter("emailAddress");
String password = req.getParameter("password");
String encryptedPassword = MD5Helper.hashPassword(password)
Customer cust = dao.findByEmailAddressAndPassword(email, encryptedPassword);
You can use something like this to encrypt the passwords using the MD5 algorithm.
public class MD5Helper {
private static final int MD5_PASSWORD_LENGTH = 16;
public static String hashPassword(String password) {
String hashword = null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password.getBytes());
BigInteger hash = new BigInteger(1, md5.digest());
hashword = hash.toString(MD5_PASSWORD_LENGTH);
} catch (NoSuchAlgorithmException nsae) {
// handle exception
}
return hashword;
}
}
You have to decide how to store passwords. If you store them as a String in a Hibernate entity, they will be stored in a varchar in database, in clear text. Anyone having access to the database will thus be able to see them. Authenticating in this case consists in comparing the sent password with the one in database.
There are two other possibilities
The first one consists in encrypting them with a secret key before storing them in database. But this secret key will have to be stored somewhere in order for your application to decrypt them and compare the decrypted password with the one sent by the user. But it could at least reduce the visibility of the password only to the persons having acces to the application deployment directory. Authenticating in this case consists in decrypting the password stored in database with the secret key, and compare it with the password sent by the user. If they are equal, then the user sent the correct password.
The last possibility would be to use a one-way hash algorithm (like SHA-1, for example), also known as message digest algorithm. This way, there is no need for a secret key, and it would be very hard (read : nearly impossible) for anyone to get access to the password (if the password is salted). The drawback of this solution is that if a user looses his password, you won't be able to send him. The only possibility is to reset him to a new value, send this new password to the user and ask him to choose a new one. Authenticating the user, in this case, consists in hashing the password he sends and comparing with the hash stored in database.
Read http://en.wikipedia.org/wiki/Salt_(cryptography) for more detailed explanations.
Usually password are stored encrypted in a database and you have to encrypt the input password to check if it matches.
String passwordEncrypted = encrypt(password);
where encrypt is your function that crypt the password (you can try with MD5 or SHA-1, for example).
After you've retrieved your object cust, you can check if
if (cust.getPassword().equals(passwordEncrypted)) {
// login successfull code
} else {
// login failed code
}