I make this code for change password with verification. The problem is, when I clicked jbutton to change password, it works and successfully changed the password on database and show the jOptionpane Information message as well.
But after this steps, error message functioned jOptionpane is continuously showing. I try to find where the code was wrong. but couldn't yet.
private void jBtn_UpdateActionPerformed(java.awt.event.ActionEvent evt) {
String user_id = txt_UserID.getText();
String cur_pass = txt_CurrentPassword.getText();
String new_pass = txt_NewPassword.getText();
try {
Connection c = DBConnection.dbconmethod();
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT * from tch_data");
while(rs.next()) {
String userid = rs.getString("user_id");
String pass = rs.getString("password");
if(user_id.equals(userid) && cur_pass.equals(pass)) {
Statement s1 = c.createStatement();
s1.executeUpdate("UPDATE tch_data SET password='"+new_pass+"' WHERE user_id='"+user_id+"'");
JOptionPane.showMessageDialog(new view.AdminPrivacy(), "Password Succesfully Changed!", null, JOptionPane.INFORMATION_MESSAGE);
}else {
JOptionPane.showMessageDialog(new view.AdminPrivacy(), "Error : Invalid Data.", "Error Message", JOptionPane.ERROR_MESSAGE);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
You're retrieving all the rows in the database, for all the users, with your SQL query
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT * from tch_data");
Of course your username and password do not match all the rows (since you'll be seeing all the users in your database in your loop) so you always get an error message for each row except for the one that has your user in it.
You should change the query to only return the row for the user that you're changing the password for. However that requires you to use a PreparedStatement. (If you simply used the user_id in the query for a regular Statement without escaping, you'd make yourself subject to SQL injection attacks. Note that also applies to the place where you update the password - you should also use a PreparedStatement for that, otherwise you'll be in for a nasty surprise when somebody changes his password to '; DROP TABLE tch_data; SELECT * FROM tch_data 'foobar or something along those lines)
So you should replace the above two lines with these 3 lines:
PreparedStatement st = c.prepareStatement("SELECT * from tch_data WHERE user_id = ?");
st.setString(1, user_id);
ResultSet rs = st.executeQuery();
Note that you've also forgotten to close your ResultSet, Statement and Connection. You should close all of them (but most importantly the Connection), otherwise you're leaking them and your application will quickly run out of resources.
Once the Password change has been successfully made, you should break out of the while loop using the break statement. The else statement within the while loop should also be removed and placed outside of the loop. A boolean flag should be set so as to determine whether or not a successful password change has taken place and that condition checked outside the loop, for example:
try {
Connection c = DBConnection.dbconmethod();
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("SELECT * from tch_data");
boolean success = false; // **** Added Code ****
while(rs.next() && success == false) {
String userid = rs.getString("user_id");
String pass = rs.getString("password");
if(user_id.equals(userid) && cur_pass.equals(pass)) {
Statement s1 = c.createStatement();
s1.executeUpdate("UPDATE tch_data SET password='"+new_pass+"' WHERE user_id='"+user_id+"'");
success = true; // **** Added Code ****
JOptionPane.showMessageDialog(new view.AdminPrivacy(), "Password Succesfully Changed!", null, JOptionPane.INFORMATION_MESSAGE);
break; // **** Added Code ****
}
}
// **** Added Code ****
if (!success) {
JOptionPane.showMessageDialog(new view.AdminPrivacy(), "Error : Invalid Data.", "Error Message", JOptionPane.ERROR_MESSAGE);
}
} catch (Exception e) { e.printStackTrace(); }
I fully agree with Erwin Bolwidt's answer, and it is IMHO the correct answer.
Since you also asked why you end up with messagedialogues --> because you're loading all users!!!
and your if-else block is wrong. if you're only changing/checking the password for one single user!
// make sure that it's the correct user
if(user_id.equals(userid)) {
// check if password was changed successfully
if(cur_pass.equals(pass)) {
// successful password change
} else {
// something went wrong with the password change
}
} else {
// this else is just to help you see your mistake
// in your code you raised the error here!
}
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.
String email = email_register_txt.getText();
String username = username_register_txt.getText();
Statement stmt = db_connection.connect().createStatement();
String sql = "SELECT * FROM user_profile WHERE username=' "+username+" ' OR user_email=' "+email+" ' ";
res = stmt.executeQuery(sql);
if(res.next()) {
if(res.getString("username").equalsIgnoreCase(username)) {
JOptionPane.showMessageDialog(registerPanel, "The username has already been already registered!");
} else if (res.getString("user_email").equalsIgnoreCase(email)) {
JOptionPane.showMessageDialog(registerPanel, "This email address has already been already registered!");
}
} else { ...
Either of those error message appear when i enter the username/email who has already been inserted into the database.
My register work but I think the verify part may be missing something?
You are obviously not showing all the pertinent code or you simply have neglected to place the needed code into your method that should make this work.
A ResultSet is basically a collection of results from your query which you need to iterate through to access all results from that query. A while loop is widely used as the means to iterate through all the results contained within a result set object. I see nowhere in your code where you have declared a ResultSet Object but yet you are trying to utilize one. Perhaps try something like this:
String email = email_register_txt.getText();
String username = username_register_txt.getText();
try {
Connection conn = DriverManager.getConnection("...your jdbc connection string...");
conn.setAutoCommit(false);
String sql = "SELECT * FROM user_profile WHERE username = ? OR user_email = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, email);
ResultSet res = stmt.executeQuery();
// Utilize a boolean Flag to indicate whether
// or not the User is registered.
boolean registered = false;
while (res.next()) {
if(res.getString("username").equalsIgnoreCase(username)) {
JOptionPane.showMessageDialog(registerPanel,
"The username has already been already registered!");
registered = true;
break; // Get out of the loop. No more need for it.
}
else if(res.getString("user_email").equalsIgnoreCase(email)) {
JOptionPane.showMessageDialog(registerPanel,
"This email address has already been already registered!");
registered = true;
break; // Get out of the loop. No more need for it.
}
}
// Do what needs to be done if User is NOT registered.
if (!registered) {
...............................
...............................
}
res.close();
stmt.close();
conn.close(); //Close the DB connection
}
catch (SQLException ex) {
ex.printStackTrace();
}
You will notice the use of the PreparedStatement Class. There are a number of benefits for using this class:
1) PreparedStatement allows you to write dynamic and parametric queries.
2) PreparedStatement is faster than Statement in Java.
3) PreparedStatement prevents SQL Injection Attacks in Java
Read more about Why to use Prepared Statements in Java here.
Searched for an answer to this but can't find anything similar. Checked the questions which may already have my answer as well but again no solution.
So first of all, here is the code which doesn't complete:
Class.forName(DRIVER);
Connection connection = DriverManager.getConnection(URL, USER,
PASS);
Statement statement = connection.createStatement();
e = email.getText();
p = password.getText();
String SQL = "SELECT email, password FROM healthcareProfessional WHERE email = '" + e
+ "' AND password = '" + p + "';";
ResultSet resultSet = statement.executeQuery(SQL);
while (resultSet.next()) {
if (email.getText().equals(resultSet.getString("email"))
&& password.getText().equals(resultSet.getString("password"))) {
Main.applyHomescreenLayout();
} else if (email.getText().equals("") || password.getText().equals("")) {
errorMessage.setText("Incorrect Email.");
errorMessage.setTextFill(Color.RED);
FadeTransition fadeTransition = new FadeTransition(Duration.millis(3000.0), errorMessage);
fadeTransition.setFromValue(3000.0);
fadeTransition.setToValue(0.0);
fadeTransition.playFromStart();
}
}
Everything here works fine provided I enter valid login credentials. However, if I leave the email or password blank and try to log in, no message is displayed and I can't understand why. Can anyone point me in the right direction?
Also, if I remove the connection the below code works perfectly and the message is displayed.
if (email.getText().equals("") || password.getText().equals("")) {
errorMessage.setText("Incorrect Email or Password.");
errorMessage.setTextFill(Color.RED);
FadeTransition fadeTransition = new FadeTransition(Duration.millis(3000.0), errorMessage);
fadeTransition.setFromValue(3000.0);
fadeTransition.setToValue(0.0);
fadeTransition.playFromStart();
}
I have also tried closing the resultset, statement and connection within the if and else if statements, replacing the .equals("") with .isEmpty(), and using separate resultsets, none of which worked.
First of all this check must be before checking Database, i.e. before execution of DB query to check for user credentials.
if (email.getText().equals("") || password.getText().equals("")) {
errorMessage.setText("Incorrect Email.");
errorMessage.setTextFill(Color.RED);
FadeTransition fadeTransition = new FadeTransition(Duration.millis(3000.0), errorMessage);
fadeTransition.setFromValue(3000.0);
fadeTransition.setToValue(0.0);
fadeTransition.playFromStart();
}
You must not allow anyone with no password or no email id to sniff your database check.
Secondly but your DB connection in try catch block and in finally block release all connection objects,statement objects.
Thirdly use prepared statement to protect your system from sql injections.It is not good practice to create query in this way.
https://docs.oracle.com/javase/tutorial/jdbc/basics/prepared.html
Do you get any message when the email and password are not blank but does not match?
It seems that if there is no matching combination the resultSet will be empty and next() will always evaluate as false, completely skipping the while loop.
What I would do (no compiler here, so the code can have mistakes) is:
ResultSet resultSet = statement.executeQuery(SQL);
if (resultSet.next()) {
//No need to re-validate
Main.applyHomescreenLayout();
} else {
//no email|password combination found on database
errorMessage.setText("Incorrect Email.");
errorMessage.setTextFill(Color.RED);
FadeTransition fadeTransition = new FadeTransition(Duration.millis(3000.0), errorMessage);
fadeTransition.setFromValue(3000.0);
fadeTransition.setToValue(0.0);
fadeTransition.playFromStart();
}
This was said before but is always good to be reinforced: take a look at prepared statements to avoid sql injections.
Your else block is essentially unreachable.
Your SQL statement selects only rows in the database table for which the database email field is equal to the text in the email text field, and for which the database password field is equal to the text in the password text field (or PasswordField, presumably).
So if the user leaves either email or password blank, it will select only rows from the database for which email is blank or password is blank, respectively. In that case, for any row in the result set, the test
if (email.getText().equals(resultSet.getString("email"))
&& password.getText().equals(resultSet.getString("password")))
will still evaluate to true, so you won't reach the else block. If there are no such rows in the database table, then you simply get an empty result set and your while loop iterates zero times, so you won't reach the else block (or even the if block) under those conditions either.
Inside my Add button click i have typed some codes which works very well and inside my try catch block i have two JOptionPane messages. 1st message is to say that info has been added sucessfully and the other which is inside the catch block is to say that Client cannot be added twice to the same tour on same date.
When I run this code without any primary key violations it shows the 1st message (which is correct) but also shows the 2nd message as well. It should show only 1st message and stop. But after showing both messages it adds to the database.
When I enter something that will give primary key violation, it shows add successfully message( which is wrong) and then the Error message. It doesnt add to the database.
What am I doing wrong?
Here is my code.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
DBConnection db = new DBConnection();
if (txt_name.getText().isEmpty() || txt_escort.getText().isEmpty()) {
JOptionPane.showMessageDialog(null, "Cannot have empty fields");
} else {
clientID = combo_client.getSelectedItem().toString();
tourID = combo_tour.getSelectedItem().toString();
date = combo_date.getSelectedItem().toString();
escortID = txt_escort.getText();
clientName = txt_name.getText();
try {
query = "INSERT INTO tourRParticipant(ClientID,Name,TourID,StartDate,EscortID) VALUES (?,?,?,?,?)";
PreparedStatement stm = db.getconn().prepareStatement(query);
JOptionPane.showMessageDialog(null, "Added successfully!");
stm.setString(1, clientID);
stm.setString(2, clientName);
stm.setString(3, tourID);
stm.setString(4, date);
stm.setString(5, escortID);
rs = stm.executeQuery();
rs.next();
conn.close();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, "ERROR..Client cannot be added to the same tour with the same date");
}
ViewTable();
}
}
First of all, you display the success message JOptionPane.showMessageDialog(null, "Added successfully!"); before executing the update. It should be displayed after the insert statement is executed.
Second of all, you should call executeUpdate not executeQuery, since you are executing an INSERT statement.
stm.executeUpdate();
JOptionPane.showMessageDialog(null, "Added successfully!");
JOptionPane.showMessageDialog(null, "Added successfully!");
should be after
rs = stm.executeQuery();
And as pointed in other answer, stmt.executeUpdate() should be used instead of stmt.executeQuery(). As you are passing an update query to executeQuery() method, it is throwing exception. That's why you are always getting two messages.
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");}