import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.PreparedStatement;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
//data base consists of columns [ID, username, password]
public class DataBaseController {
private static final int MAX_USERNAME_LENGTH = 20;
private static final int MIN_USERNAME_LENGTH = 5;
private static final int MAX_PASSWORD_LENGTH = 30;
private static final int MIN_PASSWORD_LENGTH = 7;
public static final int CORRECT_PASSWORD_RETURN_VAL = 1;
public static final int INCORRECT_PASSWORD_RETURN_VAL = 2;
public static final int MAX_PASSWORD_RESETS_REACHED_RETURN_VAL = 3;
public static final int WEAK_PASSWORD_RETURN_VAL = 4;
public static final int WEAK_USERNAME_RETURN_VAL = 5;
public static final int USER_ALREADY_EXISTS_RETURN_VAL = 6;
public static final int USER_NOT_EXISTS_RETURN_VAL = 7;
private static final int USERNAME_INDEX = 2;
private static final int PASSWORD_INDEX = 3;
private static final int PASSWORD_RESET_INDEX = 4;
private static final int RESET_TIMER_INDEX = 5;
private static final int MAX_PASSWORD_RESETS = 3;
private static final long RESET_TIME_TO_ADD = 20000L;
private static final String ROOT_NAME = "root";
private static final String DB_PASSWORD = "samgy2010";
private static final String DB_NAME = "mydb";
Connection con;
public DataBaseController() throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
this.con = DriverManager.getConnection("jdbc:mysql://localhost:3306/" + DB_NAME, ROOT_NAME,DB_PASSWORD);
}
public boolean authorizeUser(String username, String password) throws Exception {
/*Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/" + DB_NAME, ROOT_NAME,DB_PASSWORD);*/
String hashedPassword = new String(passwordHash(password), "UTF-8");
System.out.println(hashedPassword);
String query = "SELECT * FROM users WHERE username=?";
PreparedStatement stmt = this.con.prepareStatement(query);
stmt.setString(1, username);
ResultSet rs = stmt.executeQuery();
boolean userExists = rs.next();
boolean correctLogin = false;
if(userExists) {
correctLogin = rs.getString(USERNAME_INDEX).equals(username) && rs.getString(PASSWORD_INDEX).equals(hashedPassword);
}
return correctLogin;
}
public int register(String username, String password) throws ClassNotFoundException, SQLException, NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
if(!checkIfUsernameValid(username)) {
return WEAK_USERNAME_RETURN_VAL;
}
if(!checkIfPasswordValid(password)) {
return WEAK_PASSWORD_RETURN_VAL;
}
/*Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/" + DB_NAME + "?verifyServerCertificate=false&useSSL=true", ROOT_NAME, DB_PASSWORD);*/
String hashedPassword = new String(passwordHash(password), "UTF-8");
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement stmt = this.con.prepareStatement(query);
stmt.setString(1, username);
ResultSet rs = stmt.executeQuery();
boolean doesUserExists = rs.next();
if(!doesUserExists) {
Statement idCheck = con.createStatement();
String numberOfUsersQuery = "SELECT COUNT(*) FROM users";
ResultSet userIDRs = idCheck.executeQuery(numberOfUsersQuery);
String addUserSql = "";
userIDRs.next();
int newID = 1 + userIDRs.getInt(1);
//addUserSql = "INSERT INTO users(ID, username, password) VALUES(" + newID +", " + "'" + username + "'" + ", " + "'" + password + "');";
addUserSql = "INSERT INTO users(ID, username, password) VALUES(?, ?, ?)";
stmt = this.con.prepareStatement(addUserSql);
stmt.setInt(1, newID);
stmt.setString(2, username);
stmt.setString(3, hashedPassword);
stmt.executeUpdate();
}
if(doesUserExists) {
return USER_ALREADY_EXISTS_RETURN_VAL;
}
return USER_NOT_EXISTS_RETURN_VAL;
}
public int resetPassword(String username, String oldPassword, String newPassword) throws ClassNotFoundException, SQLException {
/*Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/" + DB_NAME + "?verifyServerCertificate=false&useSSL=true", ROOT_NAME, DB_PASSWORD);*/
String checkUserQuery = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = this.con.prepareStatement(checkUserQuery);
stmt.setString(1, username);
stmt.setString(2, oldPassword);
ResultSet rs = stmt.executeQuery();
if(!rs.next()) {
return INCORRECT_PASSWORD_RETURN_VAL;
}
if(!checkIfPasswordValid(newPassword)) {
return WEAK_PASSWORD_RETURN_VAL;
}
int numOfChanges = rs.getInt(PASSWORD_RESET_INDEX);
Timestamp usersResetTimer = rs.getTimestamp(RESET_TIMER_INDEX);
System.out.println(usersResetTimer + " **** " + new Timestamp(System.currentTimeMillis()) + " **** " + usersResetTimer.after(new Timestamp(System.currentTimeMillis())));
if(!usersResetTimer.after(new Timestamp(System.currentTimeMillis()))) {
numOfChanges = 0;
}
if(numOfChanges >= MAX_PASSWORD_RESETS) {
return MAX_PASSWORD_RESETS_REACHED_RETURN_VAL;
}
String query = "UPDATE users SET password = ? WHERE username = ?";
try {
stmt = this.con.prepareStatement(query);
stmt.setString(1, newPassword);
stmt.setString(2, username);
stmt.executeUpdate();
numOfChanges += 1;
query = "UPDATE users SET numOfPasswordChanges = ? WHERE username = ?";
stmt = this.con.prepareStatement(query);
stmt.setInt(1, numOfChanges);
stmt.setString(2, username);
stmt.executeUpdate();
Timestamp newUserResetTimer = new Timestamp(System.currentTimeMillis() + RESET_TIME_TO_ADD);
System.out.println(newUserResetTimer);
String timeWithoutMillis = newUserResetTimer.toString().split("\\.")[0];
System.out.println(newUserResetTimer.toString());
query = "UPDATE users SET passwordChangeTimer = ? WHERE username = ?";
stmt = this.con.prepareStatement(query);
stmt.setString(1, timeWithoutMillis);
stmt.setString(2, username);
stmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return CORRECT_PASSWORD_RETURN_VAL;
}
private static boolean checkIfUsernameValid(String username) {
if( username == null || username.length() > MAX_USERNAME_LENGTH || username.length() < MIN_USERNAME_LENGTH)
{
return false;
}
for(int i = 0; i < username.length(); i++) {
if(!Character.isLetter(username.charAt(i)) && !Character.isDigit(username.charAt(i))) {
return false;
}
}
return true;
}
private static boolean checkIfPasswordValid(String password) {
if(password == null || password.length() > MAX_PASSWORD_LENGTH || password.length() < MIN_PASSWORD_LENGTH) {
return false;
}
boolean symbolFlag = false;
boolean digitFlag = false;
boolean letterFlag = false;
for(int i = 0; i < password.length(); i++) {
if(!Character.isLetter(password.charAt(i)) && !Character.isDigit(password.charAt(i))) {
symbolFlag = true;
}
if(Character.isLetter(password.charAt(i))) {
letterFlag = true;
}
if(Character.isDigit(password.charAt(i))) {
digitFlag = true;
}
if(symbolFlag && digitFlag && letterFlag) {
return true;
}
}
return false;
}
private static byte[] passwordHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException, UnsupportedEncodingException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest.digest(password.getBytes("UTF-8"));
return hash;
}
}
I already posted here about this project before, got feedback and want to know if the problems still persist. so I changed to prepared statement to avoid sql injecntion, I also cached my DB connection in the constructor, and finally I hashed my passwords and then sent them to the data base. did I implement it correctly? I also tried salting my passwords but I couldnt figure out how, for some reason whenever I remove the salt from the hashed password it doesnt keep its structure (I hashed a password, added salt to it and when I hash the same password and remove the salt it is not the same if I remove the salt from the original) so for now only SHA-256.