5
\$\begingroup\$

The system is pretty simple. Here is how the database looks:

 table users:
    +----------+-------------+------+-----+---------+----------------+
    | Field    | Type        | Null | Key | Default | Extra          |
    +----------+-------------+------+-----+---------+----------------+
    | userid   | int(11)     | NO   | PRI | NULL    | auto_increment |
    | username | varchar(45) | NO   | UNI | NULL    |                |
    | password | varchar(32) | NO   |     | NULL    |                |
    | email    | varchar(75) | NO   | UNI | NULL    |                |
    +----------+-------------+------+-----+---------+----------------+
    table banbyip
    +--------+-------------+------+-----+---------+-------+
    | Field  | Type        | Null | Key | Default | Extra |
    +--------+-------------+------+-----+---------+-------+
    | ipAddr | varchar(45) | YES  |     | NULL    |       |
    +--------+-------------+------+-----+---------+-------+
    table banlist
    +--------+-------------+------+-----+---------+-------+
    | Field  | Type        | Null | Key | Default | Extra |
    +--------+-------------+------+-----+---------+-------+
    | ipAddr | varchar(45) | YES  |     | NULL    |       |
    +--------+-------------+------+-----+---------+-------+
    table loginattempts
    +----------+-------------+------+-----+---------+-------+
    | Field    | Type        | Null | Key | Default | Extra |
    +----------+-------------+------+-----+---------+-------+
    | ipaddr   | varchar(45) | NO   |     | NULL    |       |
    | username | varchar(45) | NO   |     | NULL    |       |
    | count    | int(11)     | NO   |     | NULL    |       |
    +----------+-------------+------+-----+---------+-------+

Here are the jsp, they are the pages shown to the user(View): Home:

index.jsp
<!DOCTYPE html>
<html>
    <head>
        <title>Login System</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <!-- Bootstrap -->
               <!-- Latest compiled and minified CSS -->
               <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

               <!-- jQuery library -->
               <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>

               <!-- Latest compiled JavaScript -->
               <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
        <!-- End Bootstrap -->
    </head>
    <body>
        <nav class="navbar navbar-default" >
            <ul class="nav navbar-nav">
                <li class="active"><a href="index.html"> Home</a></li>
                <li><a href="login.jsp"> Login </a> </li>
                <li><a href="register.jsp"> Register </a> </li>
            </ul>
        </nav>
    </body>
</html>

Login: login.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Login</title>
        <!-- Bootstrap -->
               <!-- Latest compiled and minified CSS -->
               <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

               <!-- jQuery library -->
               <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>

               <!-- Latest compiled JavaScript -->
               <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
        <!-- End Bootstrap -->
    </head>
    <body>  
         <nav class="navbar navbar-default" >
            <ul class="nav navbar-nav">
                <li><a href="index.html"> Home</a></li>
                <li class="active"><a href="login.jsp"> Login </a> </li>
                <li><a href="register.jsp"> Register </a> </li>
            </ul>
        </nav>
         <form action="login" method="POST" role="form">
             <c:if test="${sessionScope.failed == 1}">
                 <div class="form-group">
                    <h3>Login failed</h3>
                 </div>
             </c:if>
            <div class="form-group">
                <label for="username">Username:</label>
                <input type="text" class="form-control" id="username" name="username">
            </div>
            <div class="form-group">
                <label for="password">Password:</label>
                <input type="password" class="form-control" id="password" name="password">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
        </form>
    </body>
</html>

Register:

register.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Register</title>
              <!-- Bootstrap -->
               <!-- Latest compiled and minified CSS -->
               <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">

               <!-- jQuery library -->
               <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>

               <!-- Latest compiled JavaScript -->
               <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
        <!-- End Bootstrap -->
    </head>
    <body>
         <nav class="navbar navbar-default" >
            <ul class="nav navbar-nav">
                <li><a href="index.html"> Home</a></li>
                <li><a href="login.jsp"> Login </a> </li>
                <li class="active"><a href="register.jsp"> Register </a> </li>
            </ul>
        </nav>
        <form action="register" method="POST" role="form">
            <div class="form-group">
                <c:if test="${sessionScope.Invalid_username == 1}">
                    <h6> Invalid username </h6><br />
                    <c:set var="Invalid_username" value="0" scope="session"  />
                </c:if>
                <c:if test="${sessionScope.unameAlreadyRegistered == 1}">
                    <h6> Username is already registered</h6><br />
                    <c:set var="unameAlreadyRegistered" value="0" scope="session"  />
                </c:if>
                <label for="username">Username:</label>
                <input type="text" class="form-control" id="username" name="username" placeholder="Username">
            </div>
            <div class="form-group">
                <c:if test="${sessionScope.mailAlreadyRegistered == 1}">
                    <h6> E-mail is already registered</h6><br />
                    <c:set var="mailAlreadyRegistered" value="0" scope="session"  />
                </c:if>
                <c:if test="${sessionScope.Invalid_email == 1}">
                    <h6> E-mail is invalid</h6><br />
                    <c:set var="Invalid_email" value="0" scope="session"  />
                </c:if>
                <label for="email">Email address:</label>
                <input type="email" class="form-control" id="email" name="email" placeholder="Email">
            </div>
            <div class="form-group">
                <c:if test="${sessionScope.Invalid_password == 1}">
                    <h6> Password is invalid</h6><br />
                    <c:set var="Invalid_password" value="0" scope="session"  />
                </c:if>
                <c:if test="${sessionScope.passwordsDontMatch == 1}">
                    <h6> Passwords don't match</h6><br />
                    <c:set var="passwordsDontMatch" value="0" scope="session"  />
                </c:if>
                <label for="password">Password:</label>
                <input type="password" class="form-control" id="password" name="password" placeholder="Password" >
            </div>
            <div class="form-group">
                <label for="passwordRepeat">Repeat password:</label>
                <input type="password" class="form-control" id="passwordRepeat" name="passwordRepeat" placeholder="Repeat password">
            </div>
            <button type="submit" class="btn btn-default">Submit</button>
        </form>
    </body>
</html>

banned.jsp

<!DOCTYPE html>
<%@ page contentType="text/html;charset=windows-1251"%>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/>
        <title>banned</title>
    </head>
    <body>
        You are banned
    </body>
</html>

And here are the Java classes, which are helping the servlets to do their job.

DataBase.java

package loginsystem;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DataBase {

    private final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    private final String DB_URL = "jdbc:mysql://localhost/loginsystem";
    private final String username = "root";
    private final String password = "123456";

    private Connection connection;
    private PreparedStatement statement;

    public DataBase() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection(DB_URL, username, password);
        } catch (ClassNotFoundException e) {
            System.out.println("An exception occured: " + e.toString());
        } catch (SQLException e) {
            System.out.println("An exception occured: " + e.toString());
        }
    }

    public Object[] createParams(Object... args) {
        Object params[] = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            params[i] = args[i];
        }
        return params;
    }

    public ResultSet runSQL(String sql, Object[] params, boolean isUpdate) {
        if (!validateSQL(sql, params)) {
            return null;
        }
        try {
            statement = connection.prepareStatement(sql);
            for (int i = 0; i < params.length; i++) {
                int j = i + 1;
                statement.setObject(j, params[i]);
            }
            if (isUpdate) {
                statement.executeUpdate();
                return null;
            } else {
                return statement.executeQuery();
            }
        } catch (SQLException e) {
            System.out.println(e.toString());
            return null;
        }
    }

    public int getUserId(String username) {
        String sql = "SELECT user_id FROM users WHERE username = ?;";
        int id;
        try {
            PreparedStatement ps = connection.prepareStatement(sql);
            ps.setString(1, username);
            ResultSet rs = ps.executeQuery();
            rs.next();
            id = rs.getInt("user_id");
        } catch (SQLException e) {
            System.out.print(e.toString());
            id = -1;
        }
        return id;
    }

    private boolean validateSQL(String sql, Object[] params) {
        int objectsCount = params.length;
        int questionMarks = 0;
        for (int i = 0; i < sql.length(); i++) {
            if (sql.charAt(i) == '?') {
                questionMarks++;
            }
        }
        return objectsCount == questionMarks;
    }

}

Logger.java

package loginsystem;


import java.sql.ResultSet;
import java.sql.SQLException;

public class Logger {

    private final String checkIfRecordExists = "SELECT ipaddr FROM loginattempts WHERE ipaddr = ?;";
    private final String clearRecord = "UPDATE loginattempts SET count = 0 WHERE ipaddr = ?;";
    private final String incrementRecord = "UPDATE loginattempts SET count = count + 1 WHERE ipaddr = ?";
    private final String addRecord = "INSERT INTO loginattempts(ipaddr, username, count) VALUES(?, ?, 0)";
    private final String getCountByUserName = "SELECT count FROM loginattempts WHERE  username = ?";
    private final String getCountByIp = "SELECT count FROM loginattempts WHERE ipaddr = ?";
    private final String getCount = "SELECT count FROM loginattempts WHERE ipaddr = ? AND username = ?";
    private final DataBase db = new DataBase();
    public Logger() {

    }

    public boolean checkIfRecordExists(String IP) {
        boolean retVal = false;
        ResultSet rs;
        try {
            rs = db.runSQL(checkIfRecordExists, db.createParams(IP), false);
            retVal = rs.isBeforeFirst();
        } catch (SQLException e) {
            System.out.println(e.toString());
        }
        return retVal;
    }

    public void clearRecord(String IP) {
        if (!checkIfRecordExists(IP)) {
            return;
        }
        db.runSQL(clearRecord, db.createParams(IP), true);
    }

    public void incrementRecord(String IP, String username) {
        if (!checkIfRecordExists(IP)) {
            addRecord(IP, username);
        } else {
            db.runSQL(incrementRecord, db.createParams(IP), true);
        }
    }

    public int getCountByUserName(String username) {
        int count = 0;
        try {
            ResultSet rs = db.runSQL(getCountByUserName, db.createParams(username), false);
            while (rs.next()) {
                count += rs.getInt("count");
            }
        } catch (SQLException e) {
            System.out.println(e.toString());
        }
        return count;
    }

    public int getCountByIp(String IP) {
        int count = 0;
        try {
            ResultSet rs = db.runSQL(getCountByIp, db.createParams(IP), false);
            rs.beforeFirst();
            while (rs.next()) {
                count += rs.getInt("count");
            }
            rs.close();
        } catch (SQLException e) {
            System.out.println(e.toString());
        }

        return count;
    }

    public int getCount(String IP, String username) {
        int count = 0;
        try {
            ResultSet rs = db.runSQL(getCount, db.createParams(IP, username), false);
            rs.beforeFirst();
            while (rs.next()) {
                count += rs.getInt("count");
            }
            rs.close();
        } catch (SQLException e) {
            System.out.println(e.toString());
        }

        return count;
    }

    private void addRecord(String IP, String username) {
        db.runSQL(addRecord, db.createParams(IP, username), true);
    }
}

HashingMethod.java

package loginsystem;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class HashingMethod 
{
   private MessageDigest md5;

   public HashingMethod(){
       try{
           md5 = MessageDigest.getInstance("MD5");
       }
       catch(NoSuchAlgorithmException e){
           System.out.println(e.toString());
       }
   }

   public String hashPassword(String password){
       md5.update(password.getBytes());
       byte[] digest = md5.digest();
       StringBuffer strBuff = new StringBuffer();
       for (byte b : digest) {
            strBuff.append(String.format("%02x", b & 0xff));
       }
       return strBuff.toString();
    }
}

BAN.java

package loginsystem;

import java.sql.ResultSet;
import java.sql.SQLException;

public class BAN {
    private String addBanUser = "INSERT INTO banlist VALUES(?)";
    private String removeBanUser = "DELETE FROM banlist WHERE userId = ?";
    private String isBannedUser = "SELECT * FROM banlist WHERE userId = ?";
    private String addBanIP = "INSERT INTO banbyip VALUES(?)";
    private String removeBanIP = "DELETE FROM banbyip WHERE ipAddr = ?";
    private String isBannedIP = "SELECT * FROM banbyip WHERE iAddr = ?";
    private DataBase db = new DataBase();
    public BAN(){

    }
    public void addBan(String param, boolean isIP){
        if(isIP)
            db.runSQL(addBanIP, db.createParams(db.getUserId(param)), false);
        else
            db.runSQL(addBanUser, db.createParams(db.getUserId(param)), false);
    }
    public void removeBan(String param, boolean isIP){
        if(isIP)
            db.runSQL(removeBanIP, db.createParams(db.getUserId(param)), false);
        else
            db.runSQL(removeBanUser, db.createParams(db.getUserId(param)), false);
    }
    public boolean isBanned(String param, boolean isIP){
     try{
        ResultSet rs;
        if(isIP)
            rs = db.runSQL(isBannedIP, db.createParams(db.getUserId(param)), true);
        else
             rs = db.runSQL(isBannedUser, db.createParams(db.getUserId(param)), true);
        return rs.isBeforeFirst();
     }catch(SQLException e){
         System.out.println(e.toString());
         return false;
     }
    }
}

And finally here are the servlets:

Login.java

package loginsystem;

import java.io.IOError;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletConfig;

@WebServlet(name = "Login", urlPatterns = { "/login" })
public class Login extends HttpServlet {
    private final int MAX_LEN_USERNAME = 30;
    private final int MAX_LEN_PASSWORD = 32;
    private final String validateLogin = "SELECT password FROM users WHERE username = ?";
    private Logger logger;
    private BAN ban;
    private DataBase db;
    private HashingMethod hasher;
    private static final String CONTENT_TYPE = "text/html; charset=windows-1251";

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        db = new DataBase();
        ban = new BAN();
        logger = new Logger();
        hasher = new HashingMethod();
    }
    private void failedAttempt(HttpServletRequest request, HttpServletResponse response) throws IOException{
        String username = request.getParameter("username");
        String IP = request.getRemoteAddr();
        logger.incrementRecord(IP,username);
        request.getSession().setAttribute("failed", 1);
        if(logger.getCountByUserName(username) > 10)
            ban.addBan(username, false);
        if(logger.getCountByIp(IP) > 10)
            ban.addBan(IP,true);
        response.sendRedirect("login.jsp");
    }
    private boolean validateData(String username, String password){
        if(username.equals("") || password.equals(""))
            return false;
        if(username.length() > MAX_LEN_USERNAME || password.length() > MAX_LEN_PASSWORD)
            return false;
        return true;
    }
    private boolean validateLogin(String username, String password){
        ResultSet rs;
        String passwordFromDb = "";
        try{
            rs = db.runSQL(validateLogin, db.createParams(username), false);
            rs.next();
            passwordFromDb = rs.getString("password");
        }catch(SQLException e){
            System.out.println(e.toString());
        }
       return passwordFromDb.equals(hasher.hashPassword(password));
    }
    private void succesullAttempt(HttpServletRequest request, HttpServletResponse response) throws IOException{
        response.sendRedirect("http://9gag.com");
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if(validateData(username, password)){
            if(ban.isBanned(username, false) || ban.isBanned(request.getRemoteAddr(), true))
                response.sendRedirect("banned.jsp");
            if(validateLogin(username, password)){
                succesullAttempt(request, response);
            }
            else{
                failedAttempt(request, response);
            }
        }
        else
            failedAttempt(request, response);
    }
}

Register.java

package loginsystem;

import java.io.IOException;

import java.sql.ResultSet;
import java.sql.SQLException;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet(name = "Register", urlPatterns = { "register" })
public class Register extends HttpServlet {
    private static final String CONTENT_TYPE = "text/html; charset=windows-1251";
    private final String checkIfUserExists = "SELECT username FROM users WHERE username = ?";
    private final String checkIfEmailExists = "SELECT username FROM users WHERE email = ?";
    private final String inserUser = "INSERT INTO users(username, password, email) VALUES(?, ? ,?)";
    private DataBase db = new DataBase();
    private HashingMethod hasher = new HashingMethod();

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    private boolean validateEmail(String email) {
        String EMAIL_PATTERN =
            "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
        Pattern pattern;
        pattern = Pattern.compile(EMAIL_PATTERN);
        Matcher matcher;
        matcher = pattern.matcher(email);
        return !matcher.matches();
    }

    private boolean checkIfUserExists(String username) {
        ResultSet rs;
        rs = db.runSQL(checkIfUserExists, db.createParams(username), false);
        try {
            return rs.isBeforeFirst();
        } catch (SQLException e) {
            System.out.println(e.toString());
            return true;
        }
    }

    private boolean checkIfEmailExists(String email) {
        ResultSet rs = db.runSQL(checkIfEmailExists, db.createParams(email), false);
        try {
            return rs.isBeforeFirst();
        } catch (SQLException e) {
            System.out.println(e.toString());
            return true;
        }
    }

    private boolean validateInput(String username, String password, String repeatPassword, String email,
                                  HttpSession session) {
        // username
        if (username.equals("") || username.length() > 42) {
            session.setAttribute("Invalid_username", 1);
            return false;
        }
        if (checkIfUserExists(username)) {
            session.setAttribute("unameAlreadyRegistered", 1);
            return false;
        }
        // password
        if (password.equals("")) {
            session.setAttribute("Invalid_password", 1);
            return false;
        }
        if (!password.equals(repeatPassword)) {
            session.setAttribute("passwordsDontMatch", 1);
            return false;
        }
        // email
        if (email.equals("") || validateEmail(email)) {
            session.setAttribute("Invalid_email", 1);
            return false;
        }
        if (checkIfEmailExists(email)) {
            session.setAttribute("mailAlreadyRegistered", 1);
            return false;
        }
        //else
        return true;
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = (request.getParameter("username") != null) ? request.getParameter("username") : "";
        String password = (request.getParameter("password") != null) ? request.getParameter("password") : "";
        String passwordRepeat =
            (request.getParameter("passwordRepeat") != null) ? request.getParameter("passwordRepeat") : "";
        String email = (request.getParameter("email") != null) ? request.getParameter("email") : "";
        if (validateInput(username, password, passwordRepeat, email, request.getSession())) {
            String hashedPassword = hasher.hashPassword(password);
            db.runSQL(inserUser, db.createParams(username, hashedPassword, email), true);
            response.sendRedirect("login.jsp");
        } else {
            response.sendRedirect("register.jsp");
        }
    }
}

The system is far from well written, hopefully with your help I can make it better.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Some general stuff:

Your database code is scattered around a bit. You shouldn't be passing back ResultSets. You should execute the query, read the data into a Data Object and return the object (or a list of objects).

You should also use try-catch-finally OR try-with-resources to make sure database connections are cleaned up properly.

You shouldn't store the errors in a session. Use a List<String> or String[] to hold error messages and then pass them from the Servlet to the View.

Keep your Database code contained. All your SQL statements in one class. All database operations in one class. You could have a separate class for each table you are interacting with that all use the utilities of the Database class.

You could also move you logic to 'Service Classes' and call that from the Servlet.

LoginService ls = new LoginService();

ls.validate(username, password, repeatPassword, email);

The validate method could return a list of errors (empty list means no errors).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.