How to store hashed pws into a db with Apache Shiro? - java

I have been looking all over the place with no luck to what I am trying to do.
I am looking to hash and salt my user passwords and store them into the DB. The issue is, how do I store them?
I have looked at this http://shiro.apache.org/realm.html#Realm-authentication which I have found similar answers, but it doesn't make sense.
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
...
//We'll use a Random Number Generator to generate salts. This
//is much more secure than using a username as a salt or not
//having a salt at all. Shiro makes this easy.
//
//Note that a normal app would reference an attribute rather
//than create a new RNG every time:
RandomNumberGenerator rng = new SecureRandomNumberGenerator();
Object salt = rng.nextBytes();
//Now hash the plain-text password with the random salt and multiple
//iterations and then Base64-encode the value (requires less space than Hex):
String hashedPasswordBase64 = new Sha256Hash(plainTextPassword, salt, 1024).toBase64();
User user = new User(username, hashedPasswordBase64);
//save the salt with the new account. The HashedCredentialsMatcher
//will need it later when handling login attempts:
user.setPasswordSalt(salt);
userDAO.create(user);
User nor "UserDAO" exists currently from what I'm seeing, and all of these examples seem to use older Shiro examples.
When I look at the "PasswordService" javadoc I read
Account Creation or Password Reset
Whenever you create a new user account or reset that account's password,
we must translate the end-user submitted raw/plaintext password value to a
string format that is much safer to store. You do that by calling the
encryptPassword(Object) method to create the safer value. For example:
String submittedPlaintextPassword = ...
String encryptedValue = passwordService.encryptPassword(submittedPlaintextPassword);
...
userAccount.setPassword(encryptedValue);
userAccount.save(); //create or update to your data store
Be sure to save this encrypted password in your data store
and never the original/raw submitted password.
but what is "userAccount?"
A lot of times the documentation is very vague.
However I did notice there is a "SubjectDAO" Class, but no UserDAO class...
So yeah I'm confused on what to do next, so if anyone could help me I would appreciate it greatly!
Thanks a lot!

Seems like the Documentation is refering User and UserDAO as your own User Model Entity (Table) and User Data Access Layer Entity (Class to Save, Update, Delete and Retrieve). These necessarily not required to be a part of Apache Shiro (Reason some Data Access Layer may be in RDBMS, Some in In-memory dbs, some could even be in properties file, why not?)
You must implement User and UserDAO to save to your own persistence store.
UserAccount also is the Model object you use when you want to register user accounts. Like the Gmail signup.
You must know that Apache Shiro is just a layer for Security (Authentication, Authorization, etc). Persistence must be implemented by you.
Strongly advice you to check out Spring Data JPA and Spring Security.

When you are hashing the password :
DefaultPasswordService passwordService = new DefaultPasswordService();
String encytptedPwd= passwordService.encryptPassword("your password");
Above api will generate password including salt.
Update this password using JDBC native api...
When you are implementing the JDBCRealm
PasswordMatcher credentialsMatcher = new PasswordMatcher();
this.setCredentialsMatcher(credentialsMatcher);
above will set the credential matcher and use SimpleAuthenticationInfo to validate your login.
The PasswordMatcher can be configured to use an ini file too.

Related

Create new user with privileges in database

I'm trying to implement a login feature in my project. In order to make it "secure" I whant to try to use the user system provided by phpmyadmin (my tool to manage my databases) rather than login in with the root user and then store usernames and passwords in a table and verify them etc.
I tried to add a new user in phpmyadmin and then I looked the SQL code that represented the code to add a new user :
CREATE USER 'username_test'#'localhost' IDENTIFIED WITH mysql_native_password AS '***';
GRANT SELECT ON *.* TO 'username_test'#'localhost' REQUIRE NONE WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;
GRANT ALL PRIVILEGES ON `restaurant_app`.* TO 'username_test'#'localhost';
So my goal was to use this SQL to register-login users in my app. But I can't figure out how to provide the password, I don't fully understand the first part of this command. More over, I would like you to tell me if using the phpmyadmin user feature is a good idea or if I should use the classic way to do this : connect to the database using (user:"root", passwd:"") and look into my own table containing all the users logins ?
No, it is not a good idea. You can use bcrypt to store hashed passwords instead of plain text passwords. In the bacend you would hash the password that comes from the front-end and compare that value with the one in the database.
You can read this post to see some examples.

Using MySql PASSWORD() function from hibernate

I'm rewriting old java desktop swing app to JSF application using PrimeFaces.
The old app didn't use hibernate but I have decided to use it in new app. Everything works fine but the problem is when I want to save passwords with hibernate using MySql’s function password().
Is there a way to do this because it would be nice if I could import data from old database to new database without changing passwords.
I managed to bring login to work using this code snippet:
public User login(String username, String password) {
User result = null;
Session session = HibernateUtil.getSessionFactory().openSession();
try {
String sql = "select s from User where username=:username and password=password(:password)";
Query query = session.createQuery(sql);
query.setString("username", username);
query.setString("password", password);
result = (User) query.uniqueResult();
if (result != null) {
Hibernate.initialize(result.getUserData());
}
}
finally {
session.close();
}
return result;
}
But here is problem with registration of new users since I don't know how store passwords. The code I’m using to save users to database looks like:
public User addUser(User obj) {
Session session = HibernateUtil.getSessionFactory().openSession();
try {
session.save(obj);
session.flush();
}
finally {
session.close();
}
return obj;
}
I know I could write the whole insert statement the old fashioned way but what’s the point of using hibernate then and the code would look ugly. Also I’m not happy with login snippet as well.
I’ve also tried to update password with trigger after insert but I kept getting error:
Updating of NEW row is not allowed in after trigger
So I abandoned this approach since its ugly and it doesn’t work.
Should I just use jasypt or any other library to encrypt password in applications and be done with it? Or is there an elegant solution to my problem.
The MySql function password() should not be used at all for hashing passwords! From the documentation:
The PASSWORD() function is used by the authentication system in MySQL
Server; you should not use it in your own applications.
The calculation is fast and unsalted, which makes it very unsecure. Instead leave the hashing to the server side language and use a library which uses a slow hash function with a cost factor like BCrypt, PBKDF2 or SCrypt. A wellknown library for Java is jBCrypt.
Using Jasypt EncryptedStringType is much more convenient, since you delegate the password hashing to the UserType.
This way your application logic doesn't have to deal with password related responsibilities (like it's the case of your SELECT using the non-portable PASSWORD SQL function).
The UserType will also take care of hashing the actual password for an INSERT/UPDATE too.
So, Jasypt is a much better alternative.

Google App Engine HRD query without ancestor

I have a GAE project written in Java and I have some thoughts about the HRD and a problem that I'm not sure how to solve.
Basically I have users in my system. A user consists of a userid, a username, an email and a password. Each time I create a new user, I want to check that there isn't already a user with the same userid (should never happen), username or email.
The userid is the key, so I think that doing a get with this will be consistent. However, when I do a query (and use a filter) to find possible users with the same username or email, I can't be sure that the results are consistent. So if someone has created a user with the same username or email a couple of seconds ago, I might not find it with my query. I understand that ancestors are used to work around this problem, but what if I don't have an ancestor to use for the query? The user does not have a parent.
I'd be happy to hear your thoughts on this, and what is considered to be best practice in situations like these. I'm using Objectify for GAE if that changes anything.
I wouldn't recommend using email or any other natural key for your User entity. Users change their email addresses and you don't want to end up rewriting all the foreign key references in your database whenever someone changes their email.
Here's a short blurb on how I solve this issue:
https://groups.google.com/d/msg/google-appengine/NdUAY0crVjg/3fJX3Gn3cOYJ
Create a separate EmailLookup entity whose #Id is the normalized form of an email address (I just lowercase everything - technically incorrect but saves a lot of pain when users accidentally capitalize Joe#example.com). My EmailLookup looks like this:
#Entity(name="Email")
public class EmailLookup {
/** Use this method to normalize email addresses for lookup */
public static String normalize(String email) {
return email.toLowerCase();
}
#Id String email;
#Index long personId;
public EmailLookup(String email, long personId) {
this.email = normalize(email);
this.personId = personId;
}
}
There is also a (not-normalized) email field in my User entity, which I use when sending outbound emails (preserve case just in case it matters for someone). When someone creates an account with a particular email, I load/create the EmailLookup and the User entities by key in a XG transaction. This guarantees that any individual email address will be unique.
The same strategy applies for any other kind of unique value; facebook id, username, etc.
A way around the HRD's eventual consistency, is to use get instead of query. To be able to do this is you need to generate natural IDs, e.g. generate IDs that consists of data you receive in request: email and username.
Since get in HRD has strong consistency, you will be able to reliably check if user already exists.
For example a readable natural ID would be:
String naturalUserId = userEmail + "-" + userName;
Note: in practice emails are unique. So this is a good natural ID on it's own. No need to add a made-up username to it.
You may also enable cross-group transactions (see https://developers.google.com/appengine/docs/java/datastore/overview#Cross_Group_Transactions) and then in one transaction look for the user and create a new one, if that helps.
Recommend avoiding an indexed field and query unless you have other uses for it. Here is what I have done before (Python) using key_name (since entity ids need to be ints). Easy to use either the key_name or id for other entities that need to link to user:
username = self.request.get('username')
usernameLower = username.lower()
rec = user.get_by_key_name(usernameLower)
if rec is None:
U = user(
key_name = usernameLower,
username = username,
etc...)
U.put()
else:
self.response.out.write(yourMessageHere)

how to get/set the salt for a JdbcRealm

I am attempting to use the Shiro JdbcRealm and SHA256 hashedcredentialsMatcher. I need to update a legacy database and assign the appropriate salt for each user (via a batch routine).
how do I get/set the salt for a given account using the Shiro framework?
With Shiro 1.2.3 all you need to do is:
Extend JdbcRealm and set salt style.
public class JdbcSaltRealm extends JdbcRealm {
public JdbcSaltRealm() {
setSaltStyle(SaltStyle.COLUMN);
}
}
Update shiro.ini to use extended realm and to get salt column from DB
credentialsMatcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName = SHA-256
jdbcRealm = com.mypackage.JdbcSaltRealm
jdbcRealm.authenticationQuery = SELECT password, salt FROM user WHERE username = ?
jdbcRealm.credentialsMatcher = $credentialsMatcher
Hash & salt current / new user passwords. This should be done for all existing users as well as on new user registrations.
private void saltHashPassword(String password) {
String salt = new BigInteger(250, new SecureRandom()).toString(32);
//TODO: save salt value to "salt" column in user table
Sha256Hash hash = new Sha256Hash(password,
(new SimpleByteSource(salt)).getBytes());
String saltedHashedPassword = hash.toHex();
//TODO: save saltedHashedPassword value to "password" column in user table
}
I hope my answer is clear and understandable.
Maybe a bit late:
Have a look at this tutorial.
Meri, the guy who owns the blog, describes exactly how to create an own salted JDBC Realm.
This is also an acknowledged improvement in the community for version 1.3.0 .
Hope this helpes, have Fun!

Why isn't the database being updated when I refresh the entity manager?

I'm currently developing a social networking site and I'm currently implementing the part where a user can change his password. I'm using the entity manager to refresh the contents of the database with the new password. The following is the code for the implementation.
final Implementation user = em.find(Implementation.class, username);
if((user!=null) && user.getPassword().equals(hash(username,oldPassword))){
user.setPassword(hash(username,newPassword));
em.refresh(user);
}else{
throw new ChangePasswordException();
}
however when I try to login again, the older password must be used, otherwise, if the new password is supplied it will tell you: passwords do not match. Does anyone know maybe why this is happening? I tried to first remove the user from the database, and then persist the new user again. However an EJB Exception was generated as the username was not unique since the user was not removed from the database.
Thanks a lot for your help
You are not saving your new password. You are overwriting your changes you have made. So refresh(user) will fetch the current state of that user and will write it into your object.
docu: Refresh the state of the instance from the database, overwriting changes made to the entity, if any.
Try to use merge or persist instead

Categories