Skip to main content
1 of 3
Ellie
  • 587
  • 3
  • 8

Is my database file correctly structured? [V2]

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.

Ellie
  • 587
  • 3
  • 8