I working on a log in system in Java and I am using PostgreSQL. I have a registration form that saves the user information to the database. It also hashes the password before storing. I am now trying to verify the password that the user enters against the hashed password in the database.
try {
//connects to the database
Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/cc", "pi", "server");
//prepares SELECT statement
PreparedStatement statement = conn.prepareStatement("SELECT username, user_pass FROM users WHERE username = '" + username +"';");
ResultSet result = statement.executeQuery();
String upass = new String(password.getPassword());
String user = "";
String pass = "";
while(result.next()){
user = result.getString("username");
pass = result.getString("user_pass");
}
if(username.equals(user) && BCrypt.checkpw(upass, pass)){
frame.dispose();
new CommunityCooks();
}
else{
JOptionPane.showMessageDialog(null, "incorrect credentials");
}
}
catch(SQLException f){
f.printStackTrace();
}
This is the section that I am trying to verify the password matches. The "password" variable is a JPasswordField and the "username" variable is a JTextField. The stored credentials are 'tester' for the username and password and I am able to verify them as local variables and fields. I think the issue I am having is with the translation of the JTextField and the JPasswordField. What I am looking for help on is getting the username and password that the user enters to verify against the stored credentials after the password is hashed from the registration form. The issue I am having is that I can run the application and the login frame opens. I enter the test credentials and it is not matching. I’m getting my incorrect credentials message. I am unclear about the syntax for comparing the stored username (not hashed) and the stored password (hashed) against the user input credentials in the JTextField and the JPasswordField. I thought what I had was correct but it appears to not be right. The testing I have done for it works to read the database and verify but it is not working when I implement it in my program. The only difference in the two is the use of the fields where the test did not use them. My test is below:
public class Main {
public static void main(String[] args) {
String firstName = "tester";
String lastName = "tester";
String email = "tester";
String username = "tester";
String password = "tester";
try {
//connects to the database
Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/cc", "pi", "server");
//inserts values into table
PreparedStatement statement = conn.prepareStatement("insert into users values(?,?,?,?,?)");
statement.setString(1, firstName);
statement.setString(2, lastName);
statement.setString(3, email);
statement.setString(4, username);
statement.setString(5, BCrypt.hashpw(password, BCrypt.gensalt()));
PreparedStatement st = conn.prepareStatement("SELECT username, user_pass FROM users WHERE username = '" + username + "';");
ResultSet result = st.executeQuery();
String u = null;
String p = null;
while (result.next()) {
u = result.getString("username");
p = result.getString("user_pass");
}
System.out.println(u);
System.out.println(p);
System.out.println(BCrypt.checkpw(password, p));
} catch(SQLException f){
f.printStackTrace();
}
}
}
The test output works and shows the username and the hashed password and stating that it is "true" to being verified.
Any guidance will be greatly appreciated. This is my first time using a hash system.
Related
I am trying to create a Login and Register form using Java and SQL Workbench. The Register form works properly as the Username and Password are added to the SQL Database. As for the Login form, everything looks fine. But, when it is executed, it skips the If Statement and goes straight to the Else Statement. The Username and Password are correct as I checked the SQL Database table. The output is a SqlSyntaxErrorException. Therefore, I think my syntax is wrong. Any help would be highly appreciated!
This is the code below:
if (e.getSource() == LOG_IN_BUTTON)
{
String userName = USER_NAME_TEXTFIELD.getText();
String password = PASSWORD_TEXTFIELD.getText();
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/airline_connect",
"root", "Yasser1595");
String sql = "Select user_name, password from account where user_name=? and password=?";
st = connection.prepareStatement(sql);
st.setString(1, userName);
st.setString(2, password);
ResultSet rs = st.executeQuery(sql);
if (rs.next()) {
frame.dispose();
new MainGame();
JOptionPane.showMessageDialog(LOG_IN_BUTTON, "You have successfully logged in");
} else {
JOptionPane.showMessageDialog(LOG_IN_BUTTON, "Wrong Username & Password");
}
} catch (Exception exc) {
exc.printStackTrace();
}
}
Try the following,
ResultSet rs = st.executeQuery();
Don't pass the sql string to executeQuery. When you pass the sql string to executeQuery it considers it as plain text instead of prepared statement
You did not use PreparedStatement.executeQuery() but the parent's Statement.executeQuery(sql) which is a known pitfall. Also it is worth using try-with-resources with local variables. Not closing things can cause resource leaks.
String sql = "select user_name, password from account where user_name=? and password=?";
try (Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/airline_connect",
"root", "Yasser1595");
PreparedStatement st = connection.prepareStatement(sql)) {
st.setString(1, userName);
st.setString(2, password);
try (ResultSet rs = st.executeQuery()) { // No sql parameter.
if (rs.next()) {
frame.dispose();
new MainGame();
JOptionPane.showMessageDialog(LOG_IN_BUTTON, "You have successfully logged in");
return;
}
JOptionPane.showMessageDialog(LOG_IN_BUTTON, "Wrong Username & Password");
}
} catch (SQLException exc) {
exc.printStackTrace();
}
It still did not work
PASSWORD also is a function, but as no syntax errors happend, that probably is no problem. You might try "password" (= column name).
The column might store not the password - which is a security risk, should
the database be stolen in the future. It might store some hash of the password.
So:
String sql = "SELECT user_name, \"password\" "
+ "FROM account "
+ "WHERE user_name=? AND \"password\"=PASSWORD(?)";
First check how passwords (or their hashes) are stored.
It might also be the case that the password handling is done at the java side, for instance by taking the MD5 of the password and storing that.
Should all work, consider an other securite measure: if the password field is a JPasswordField one should ideally not work with a String, but a char[] that can be wiped out after usage (Arrays.setAll(pwdArray, ' ');). A String could reside long in memory, which might be a security risk.
I am playing around with a login/register system for a desktop application. I have a register form and sign in form and the credential information is saved to a PostgreSQL database. I started out without encrypting information and everything is working but I now want to encrypt the password to save to the database. I am using Jasypt and got the password to encrypt and save to the database:
public void actionPerformed(ActionEvent e){
if(e.getSource() == registerButton){
try{
//connects to the database
Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/cc","pi","server");
//inserts values into table
PreparedStatement statement = conn.prepareStatement("insert into users values(?,?,?,?,?)");
statement.setString(1, firstName.getText());
statement.setString(2, lastName.getText());
statement.setString(3, email.getText());
statement.setString(4, username.getText());
//checks password to ensure confirmation matches
//encrypts password for storing in database
if(password.getText().equals(confPass.getText())){
StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();
String encryptPass = passwordEncryptor.encryptPassword(password.toString());
statement.setString(5, encryptPass);
statement.executeUpdate();
JOptionPane.showMessageDialog(null, "Registered Successfully");
frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
}
else{
JOptionPane.showMessageDialog(null, "Password did not match");
}
} catch(SQLException f){
f.printStackTrace();
}
}
This works well and my password is encrypted. I am stumped on where to begin with getting the password from the database to compare the encrypted password to the user input. My sign in form to compare passwords (prior to encrypting the password):
public void actionPerformed(ActionEvent e){
//verify users credentials and signs in
if(e.getSource() == login){
try{
//connects to the database
Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/cc","pi","server");
//inserts values into table
PreparedStatement statement = conn.prepareStatement("SELECT username, user_pass FROM users WHERE username = ? and user_pass = ?");
statement.setString(1, username.getText());
statement.setString(2, password.getText());
ResultSet result = statement.executeQuery();
if (result.next()) {
frame.dispose();
new CommunityCooks();
}
else {
JOptionPane.showMessageDialog(null, "Username or Password did not match.");
}
}
catch(SQLException f){
f.printStackTrace();
}
}
I made a test app to compare encrypted passwords and have a general idea of how it works:
import org.jasypt.util.password.StrongPasswordEncryptor;
public class EncryptTest {
public static void main(String[] args) {
String userPass = "test";
StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();
String encryptPass = passwordEncryptor.encryptPassword(userPass);
System.out.println(encryptPass);
if(passwordEncryptor.checkPassword("test", encryptPass)){
System.out.println("correct");
}
else{
System.out.println("wrong");
}
}
}
The part that I am stumped on is trying to get the encrypted password and compare it to the user input password to validate. I believe I need to encrypt the input password and then can use the passworEncryptor.checkPassword(); but I don't know exactly where to put that in the sign in code and how to implement it. Any help would be great.
Thank you.
The name of the Java library Jasypt is shortened for "Java Simplified Encryption" and so this library is trying to avoid that
users are making implementations of crypto-routines that become insecure because of implementation errors.
The validation of a user password is as simple as your test app - you do not need to implement an encryption part, just pass the
password the user typed in your login form and pass it to the validation part
In details: There are two parts - in part 1 the user registers with his userPassword and passes it to the encryptPassword method:
String userPassword = "myPassword";
String encryptedPassword = passwordEncryptor.encryptPassword(userPassword);
encryptedPassword example: rCAgedhPnGoDZ1PF7hgspDIhLnLAHo536PSCKUfpYu8Yv0JHEcIZ3ZVHIHojBn1D
This encrypted password get stored in the database and you have to keep in mind that you cannot restore the original password from this string!
In part 2 the user tries to login with his loginPassword and passes it to the checkPassword method. The program loads the encryptedPassword from the database and passes the loginPassword together with the encryptedPassword. The result (boolean) is checked and the next steps in your program depend on the result, "true" means that the loginPassword is correct and "false" means that the loginPassword is not correct.
String loginPassword = "myPassword";
if (passwordEncryptor.checkPassword(loginPassword, encryptedPassword)) {
// correct!
System.out.println("correct passsword");
} else {
// bad login!
System.out.println("password not correct");
}
For more information you can check the "Easy usage" webpage: http://www.jasypt.org/easy-usage.html
I have created a login form using java servlets and jsp's. The login information such as username and password is saved in Database.
My question is that when a user enters the information that my java class fails to find in database I dont get the exception. How could I create an exception if the login data isnt available in Db?
public boolean loginValidator(String e, String p) throws SQLException {
String userName = e;
String password = p;
boolean validate = false;
try{
PreparedStatement ps = connection.prepareStatement("SELECT * FROM user WHERE email = ? and password = ?");
ps.setString(1, userName);
ps.setString(2, password);
ResultSet rst = ps.executeQuery();
while (rst.next()) {
validate = (rst.getString("email").equals(userName)) && ((rst.getString("password").equals(password)));
}}
catch(SQLException ex){
System.out.println(ex.getMessage());
validate = false;
}
return validate;
}
This is actually a method in my java class that validates and send boolean type to a servlet and later servlet decides to direct or restrict the access to application subject to the boolean type returned.
PS: A new learner of javaWeb.
And a learner of SQL, right? Because there is NO exception, if there is no such line in the DB table. The query just returns empty ResultSet. So you have to check, whether the result set is empty or not (and then alternatively check the email and password - but that is IMHO superfluous).
public boolean loginValidator(String userName, String password) {
try{
PreparedStatement ps = connection.prepareStatement("SELECT * FROM user WHERE email = ? and password = ?");
ps.setString(1, userName);
ps.setString(2, password);
ResultSet rst = ps.executeQuery();
return rst.next(); // whether DB contains such record
} catch(SQLException ex){
ex.printStackTrace(); // TIP: use logging
}
return false;
}
Btw. I would strongly recommend you NOT to store plaintext passwords in the DB.
I am trying to ensure that when a user enters username & password, authentication is done by checking if input matches some row in the user table. Here is the code so far: It doesn't respond when the login button is click. Please suggest how I can set it right. Thanks
private void dbConnection()
{
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/maths_tutor", "root", "jesus");
Statement stmt = conn.createStatement();
String CHECK_USER = "SELECT * FROM records WHERE username = '"+this.txtUser+"' AND password = '"+this.txtPass+"'";
ResultSet rs = stmt.executeQuery(CHECK_USER);
while(rs.next())
{
String user = txtUser.getText();
String pass = txtPass.getText();
if(user.equals(rs.getString("username")))
{
if(pass.equals(rs.getString("password")))
{
this.dispose();
new AboutTo().setVisible(true);
}
else JOptionPane.showMessageDialog(null, "Invalid Password");
}
else JOptionPane.showMessageDialog(null, "Invalid Username or Password");
}
stmt.close();
rs.close();
conn.close();
}
catch(SQLException | ClassNotFoundException er)
{
JOptionPane.showMessageDialog(null, "Exception:\n" + er.toString());
}
}
String CHECK_USER = "SELECT * FROM records WHERE username = '"+this.txtUser+"' AND password = '"+this.txtPass+"'";
you have passed username & password in sql query so it go in while block only if username And password will match ...
you supposed to make sql querylike this
String CHECK_USER = "SELECT * FROM records";
or you can use if block like this
if(rs.next()
{
//login successfull code
}
else
{
//login fail
}
Basically, the logic is wrong.
What you are doing is approximately this.
Get a username and a password from the user.
Ask the database for all records for which the user name is matches the supplied username and the password matches the supplied password.
For each such record:
Test if the user name matches, and open a dialog if it doesn't match. That won't happen ... because you only selected records with that user name.
Test if the password matches, and open a dialog if it doesn't match. That won't happen ... because you only selected records with that password.
What you really ought to be doing is:
Get a username and a password from the user.
Select the records that match the user name and password.
Print a message if the number of records that you matched is zero.
I should also point out some other things:
Popping up a dialog box to tell the user his user name / password are wrong is beside the point. What you really need to do is tell something else in your server that the login failed.
When the user gets just the username or just the password incorrect, you should not offer him any clues that one was correct. Doing that makes it easier for "the bad guy" to work out the correct combination.
Storing passwords in clear in a database is Bad Practice. Best practice is to store seeded hashes of the passwords ... and use a cryptographically strong hashing function.
You forgot to call getText() on txtUser and txtPass.
This is how you could fix your query:
String CHECK_USER = "SELECT * FROM records WHERE username = '" + this.txtUser.getText() + "' AND password = '" + this.txtPass.getText() + "'";
You should note that concatenation of raw input text to queries will open vulnerability to SQL injection. You should use PreparedStatement instead so that the input text is properly escaped.
The following is a way to implement this properly, however lacks the following things that should be of concern to you:
You are storing passwords in clear text. You should use a hashing function such as SHA-1.
Every authentication will result in a new connection to the database. You should probably use a proper connection pool.
.
private boolean authenticate() throws SQLException {
String dbUrl = "jdbc:mysql://localhost:3306/maths_tutor";
// This query will simply count the matching rows, instead of actually selecting
// them. This will result in less bandwidth between your application and the server
String query = "SELECT count(*) AS num_records FROM records WHERE username = ? AND password = ?";
// Obtaining the username and password beforehand could perhaps make it more clear
// and prevent errors instead of pulling the data every time you need it
String username = txtUser.getText();
String password = txtPass.getText();
// The try-with-resources block will make sure the resources are closed once we are done with
// them. More information available at
// http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
try (
// Open database connection
Connection conn = DriverManager.getConnection(dbUrl, "root", "jesus");
// Prepare the statement
PreparedStatement stmt = conn.prepareStatement(query)
) {
// Set the username and password for the SQL statement
stmt.setString(1, username);
stmt.setString(2, password);
// Execute the query in a try block, to ensure that the resources
// will be released
try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) {
// If we got 1 or more matches, this means we successfully
// authenticated. Otherwise, we failed authentication.
return rs.getInt("num_records") > 0;
}
}
}
// Failed authentication.
return false;
}
// Rename this to something meaningful according to your application
private void doAuthentication() {
try {
if (authenticate()) {
// Do successful authentication handling
this.dispose();
new AboutTo().setVisible(true);
} else {
// Do failed authentication handling
JOptionPane.showMessageDialog(null, "Invalid Username or Password");
}
} catch(SQLException er) {
// Do error handling
JOptionPane.showMessageDialog(null, "Exception:\n" + er.toString());
}
}
The possible error would be near this line
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/maths_tutor", "root", "jesus");
first make sure you have set the classpath and added the mysql driver to the project
second I would the following instead of the above, in fact why do you make things to much complex?!
java.sql.Driver _dr=new com.mysql.jdbc.Driver();
java.util.Properties _pr=new java.util.Properties();
_pr.setProperty("user","root");
_pr.setProperty("password","jesus");
Connection conn = _dr.connect("jdbc:mysql://localhost:3306/maths_tutor", _pr);
and the last thing is beware about using this like of code
String CHECK_USER = "SELECT * FROM records WHERE username = '"+this.txtUser+"' AND password = '"+this.txtPass+"'";
so here the system is ready for injection.
so the good way would be like this, using parameters.
String CHECK_USER = "SELECT * FROM records WHERE username = ? AND password = ?";//this will avoid sql injection
java.sql.PreparedStatement _st=conn.prepareStatement(CHECK_USER);
_st.setString(1, this.txtUser);
_st.setString(1, this.txtPass);
EDIT :by the way, there is no need to iterate over result set! simple just call the next() method, if it returns true, so it means user has entered correct user/pass, else otherwise.
ResultSet rs = stmt.executeQuery(CHECK_USER);
if(rs.next()){/*user exist*/
this.dispose();
new AboutTo().setVisible(true); }
else{
JOptionPane.showMessageDialog(null, "Invalid Username or Password");
}
string query = "SELECT count(*) FROM [dbo].[login1] WHERE username='" + username.Text + "' and password='" + password.Text + "'";
SqlDataAdapter sda = new SqlDataAdapter(query, con);
DataTable dt = new DataTable();
sda.Fill(dt);
if (dt.Rows[0][0].ToString() == "1")
{MessageBox.Show("YEAH");}
How could I check if the username and password (taken as input in a login page) match? All of the information is stored in a Derby DB. I just need to know if the correct password is entered for a username that is given.
Here is my code:
public void checkIdPw(String userName, String passWord) {
try {
stmt = conn.createStatement();
String checkPwforIdSQL = "SELECT PASSWORD FROM " + studentsTable + " WHERE USERNAME = '" + userName + "'";
stmt.executeQuery(checkPwforIdSQL);
stmt.close();
} catch(SQLException sqlExcept) {
sqlExcept.printStackTrace();
}
}
It is poor security to store passwords unencrypted and encrypting them with something like Bcrypt would be much better.
Something like the following should work for what you need. Using a PreparedStatement is crucial and simple string concatenation should never be done as it allows for SQL injection attacks.
PreparedStatement stmt = conn.prepareStatement(
"SELECT USERNAME FROM studentsTable WHERE USERNAME = ? AND PASSWORD = ?");
stmt.setString(1, username);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();
if (rs.next()) {
// valid credentials
} else {
// invalid credentials
}
rs.close();
stmt.close();
Depending on the nature of the site another good practice is to display the same generic message to the user on failed regardless of whether it was the username (or email address) or password that was incorrect. An example message is "Invalid username or password." The benefit to this is that it helps prevent username harvesting as the attacker would not be able to tell from the error message that the username is valid. For some sites this matters more than others and a site where the usernames are already public would not benefit as much as other harvesting methods are available.