Browse Source
- pending issue: header info box not updated right after login.feature/jQueryMainPage
13 changed files with 467 additions and 25 deletions
@ -0,0 +1,3 @@
|
||||
<Context> |
||||
<CookieProcessor sameSiteCookies="strict" /> |
||||
</Context> |
||||
@ -0,0 +1 @@
|
||||
samesite-cookie(mode=Lax) |
||||
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html><%@ |
||||
page import="java.util.Collection,org.leolo.web.dm.dao.*,org.leolo.web.dm.model.*,org.leolo.web.dm.util.*" |
||||
%><html> |
||||
<head> |
||||
<title>Download Manager</title> |
||||
</head> |
||||
<body> |
||||
<h1>Download Manager</h1> |
||||
<% Collection<Project> projs = new ProjectDao().getAllProjects(); %> |
||||
<h2>Project List</h2> |
||||
<ul><% for(Project proj:projs){ %> |
||||
<li> |
||||
<a href="project/<%=proj.getProjectPath()%>"><%= proj.getProjectName() %></a><br> |
||||
<%= JSPUtils.nl2br(proj.getDescription()) %> |
||||
</li> |
||||
<%} %></ul> |
||||
</body> |
||||
</html> |
||||
@ -1,18 +1,100 @@
|
||||
<!DOCTYPE html><%@ |
||||
page import="java.util.Collection,org.leolo.web.dm.dao.*,org.leolo.web.dm.model.*,org.leolo.web.dm.util.*" |
||||
%><html> |
||||
<head> |
||||
<title>Download Manager</title> |
||||
</head> |
||||
<body> |
||||
<h1>Download Manager</h1> |
||||
<% Collection<Project> projs = new ProjectDao().getAllProjects(); %> |
||||
<h2>Project List</h2> |
||||
<ul><% for(Project proj:projs){ %> |
||||
<li> |
||||
<a href="project/<%=proj.getProjectPath()%>"><%= proj.getProjectName() %></a><br> |
||||
<%= JSPUtils.nl2br(proj.getDescription()) %> |
||||
</li> |
||||
<%} %></ul> |
||||
</body> |
||||
<!DOCTYPE html> |
||||
<html> |
||||
<head> |
||||
<meta charset="ISO-8859-1"> |
||||
<title>Download Manager</title> |
||||
<script src="js/jquery-3.6.0.min.js"></script> |
||||
<script src="js/jquery-ui.js"></script> |
||||
<link href="js/jquery-ui.css" rel="stylesheet"> |
||||
<link href="js/main.css" rel="stylesheet"> |
||||
<script> |
||||
function updateUserInfo(){ |
||||
$.get( '<%=request.getContextPath()%>/UserInfo' , function(data){ |
||||
$('#sysname').html(data.system-name); |
||||
if(data.identified){ |
||||
//Handle userinfo box and logout link |
||||
$("#hdr-action").text("Welcome back, "+data.username); |
||||
$("#hdr-action").click(function(){ |
||||
$("#hdr-uinfo").toggle(); |
||||
}); |
||||
}else{ |
||||
//Display login link |
||||
$("#hdr-action").text("Login"); |
||||
$("#hdr-action").click(function(){ |
||||
$("#hdr-login").toggle(); |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
</script> |
||||
</head> |
||||
<body> |
||||
<nav> |
||||
Download Manager - <span id="sysname"></span> |
||||
<span class="status" id="hdr-action">Login</span> |
||||
<div class="hidden hdr-info-box ui-corner-all" id="hdr-uinfo"> |
||||
<button id="hdr-uinfo-logout">Logout</button> |
||||
</div> |
||||
<div class="hidden hdr-info-box ui-corner-all" id="hdr-login"> |
||||
<div class="hidden ui-state-error ui-corner-all" style="padding:0.3em;" id="hdr-login-msg"> |
||||
<span class="ui-icon ui-icon-alert"></span> |
||||
<span id="hdr-login-msg-cont"></span> |
||||
</div> |
||||
<table> |
||||
<tr> |
||||
<th><label for="hdr-login-username" style="white-space: nowrap;">Username</label></th> |
||||
<td><input type="text" id="hdr-login-username"></td> |
||||
</tr> |
||||
<tr> |
||||
<th><label for="hdr-login-password">Password</label></th> |
||||
<td><input type="password" id="hdr-login-password"></td> |
||||
</tr> |
||||
<tr> |
||||
<td colspan="2"><button id="hdr-login-submit">Submit</button></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
</nav> |
||||
<main> |
||||
|
||||
</main> |
||||
<script> |
||||
//Perform post-load task |
||||
updateUserInfo(); |
||||
$("#hdr-login-submit").button(); |
||||
//$("#hdr-action").button(); |
||||
$("#hdr-login-submit").click(function(){ |
||||
var uname = $("#hdr-login-username").val(); |
||||
var pass = $("#hdr-login-password").val(); |
||||
console.log("uname="+uname); |
||||
console.log("paswd="+pass); |
||||
if(uname==null || pass==null || uname=="" ||pass==""){ |
||||
//Display error message |
||||
$("#hdr-login-msg-cont").text("Username and password are required."); |
||||
$("#hdr-login-msg").show(); |
||||
return; |
||||
} |
||||
$.post('<%=request.getContextPath()%>/Login', |
||||
{username: uname, password: pass}, |
||||
function(data){ |
||||
if(data.status=="failed"){ |
||||
$("#hdr-login-msg-cont").text(data.message); |
||||
$("#hdr-login-msg").show(); |
||||
}else{ |
||||
updateUserInfo(); |
||||
$("#hdr-login-msg").hide(); |
||||
$("#hdr-login").hide(); |
||||
} |
||||
}) |
||||
}); |
||||
$("#hdr-uinfo-logout").button(); |
||||
$("#hdr-uinfo-logout").click(function (){ |
||||
$.post('<%=request.getContextPath()%>/Logout', function(data){ |
||||
updateUserInfo(); |
||||
$("#hdr-uinfo").hide(); |
||||
|
||||
}); |
||||
}); |
||||
</script> |
||||
</body> |
||||
</html> |
||||
@ -0,0 +1,82 @@
|
||||
package org.leolo.web.dm.dao; |
||||
|
||||
import java.sql.Connection; |
||||
import java.sql.PreparedStatement; |
||||
import java.sql.ResultSet; |
||||
import java.sql.SQLException; |
||||
import java.util.Hashtable; |
||||
import java.util.Map; |
||||
|
||||
import org.leolo.web.dm.Constant; |
||||
import org.leolo.web.dm.model.User; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class UserDao extends BaseDao { |
||||
|
||||
private static Logger log = LoggerFactory.getLogger(UserDao.class); |
||||
|
||||
public Map<String, Object> getBasicUserInfoByUsernameWithPassword(String username) { |
||||
Map<String, Object> u = new Hashtable<>(); |
||||
try (Connection conn = getConnection()) { |
||||
// Step 1: get basic user info
|
||||
try (PreparedStatement pstmt = conn |
||||
.prepareStatement("SELECT user_id, user_name, password, pwd_err_cnt FROM user WHERE user_name = ?")) { |
||||
pstmt.setString(1, username); |
||||
try (ResultSet rs = pstmt.executeQuery()) { |
||||
if (rs.next()) { |
||||
u.put(Constant.BUI_KEY_USER_NAME, rs.getString(2)); |
||||
u.put(Constant.BUI_KEY_USER_ID, rs.getInt(1)); |
||||
u.put(Constant.BUI_KEY_PASSWORD, rs.getString(3)); |
||||
u.put(Constant.BUI_KEY_FAIL_CNT, rs.getInt(4)); |
||||
} else { |
||||
return null; |
||||
} |
||||
} |
||||
} |
||||
} catch (SQLException e) { |
||||
log.error(e.getMessage(), e); |
||||
return null; |
||||
} |
||||
return u; |
||||
} |
||||
|
||||
public void updateLastLogin(int userId) { |
||||
try( |
||||
Connection conn = getConnection(); |
||||
PreparedStatement pstmt = conn.prepareStatement("UPDATE user SET pwd_err_cnt = 0, last_login=NOW() WHERE user_id = ?") |
||||
){ |
||||
pstmt.setInt(1, userId); |
||||
pstmt.executeUpdate(); |
||||
}catch(SQLException e) { |
||||
log.error(e.getMessage(), e); |
||||
} |
||||
|
||||
} |
||||
|
||||
public void updateLoginFailedCount(int userId) { |
||||
try( |
||||
Connection conn = getConnection(); |
||||
PreparedStatement pstmt = conn.prepareStatement("UPDATE user SET pwd_err_cnt = nvl(pwd_err_cnt,0) + 1 WHERE user_id = ?") |
||||
){ |
||||
pstmt.setInt(1, userId); |
||||
pstmt.executeUpdate(); |
||||
}catch(SQLException e) { |
||||
log.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
public void lockUser(int userId) { |
||||
try( |
||||
Connection conn = getConnection(); |
||||
PreparedStatement pstmt = conn.prepareStatement("UPDATE user SET password = concat('!!',password) WHERE user_id = ? AND password NOT LIKE '!!%'") |
||||
){ |
||||
pstmt.setInt(1, userId); |
||||
pstmt.executeUpdate(); |
||||
|
||||
}catch(SQLException e) { |
||||
log.error(e.getMessage(), e); |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -1,5 +1,42 @@
|
||||
package org.leolo.web.dm.model; |
||||
|
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
public class User { |
||||
|
||||
private String userName; |
||||
private int userId; |
||||
private String password; |
||||
|
||||
private Set<String> roles = new HashSet<>(); |
||||
|
||||
public String getUserName() { |
||||
return userName; |
||||
} |
||||
|
||||
public void setUserName(String userName) { |
||||
this.userName = userName; |
||||
} |
||||
|
||||
public int getUserId() { |
||||
return userId; |
||||
} |
||||
|
||||
public void setUserId(int userId) { |
||||
this.userId = userId; |
||||
} |
||||
|
||||
public String getPassword() { |
||||
return password; |
||||
} |
||||
|
||||
public void setPassword(String password) { |
||||
this.password = password; |
||||
} |
||||
|
||||
public Set<String> getRoles() { |
||||
return roles; |
||||
} |
||||
|
||||
} |
||||
|
||||
@ -0,0 +1,96 @@
|
||||
package org.leolo.web.dm.servlet; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
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 org.json.JSONObject; |
||||
import org.leolo.web.dm.Constant; |
||||
import org.leolo.web.dm.dao.SystemParameterDao; |
||||
import org.leolo.web.dm.dao.UserDao; |
||||
import org.leolo.web.dm.util.QueuedJobs; |
||||
import org.leolo.web.dm.util.ServletUtil; |
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
import org.slf4j.Marker; |
||||
import org.slf4j.MarkerFactory; |
||||
|
||||
import at.favre.lib.crypto.bcrypt.BCrypt; |
||||
|
||||
/** |
||||
* Servlet implementation class LoginServlet |
||||
*/ |
||||
@WebServlet("/Login") |
||||
public class LoginServlet extends HttpServlet { |
||||
private static Logger log = LoggerFactory.getLogger(LoginServlet.class); |
||||
private static Marker mark = MarkerFactory.getMarker("user"); |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
/** |
||||
* @see HttpServlet#HttpServlet() |
||||
*/ |
||||
public LoginServlet() { |
||||
super(); |
||||
// TODO Auto-generated constructor stub
|
||||
} |
||||
|
||||
/** |
||||
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) |
||||
*/ |
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { |
||||
// TODO Auto-generated method stub
|
||||
UserDao udao = new UserDao(); |
||||
SystemParameterDao spdao = new SystemParameterDao(); |
||||
log.info("Login attempted! {}@{}:{}", request.getParameter("username"), request.getRemoteHost(), request.getParameter("password")); |
||||
Map<String, Object> bui = udao.getBasicUserInfoByUsernameWithPassword(request.getParameter("username")); |
||||
if(bui!=null) { |
||||
if(BCrypt.verifyer().verify(request.getParameter("password").toCharArray(), bui.get(Constant.BUI_KEY_PASSWORD).toString().toCharArray()).verified) { |
||||
log.info(mark, "User {}@{} logged in successfully!", bui.get(Constant.BUI_KEY_USER_NAME), ServletUtil.getClientIpAddr(request)); |
||||
request.getSession().setAttribute(Constant.SESSION_USER_ID, (int)bui.get(Constant.BUI_KEY_USER_ID)); |
||||
request.getSession().setAttribute(Constant.SESSION_USER_NAME, bui.get(Constant.BUI_KEY_USER_NAME)); |
||||
sendSuccessResponse(response); |
||||
QueuedJobs.getInstance().queue(()->{ |
||||
udao.updateLastLogin((int)bui.get(Constant.BUI_KEY_USER_ID)); |
||||
}); |
||||
}else { |
||||
log.info(mark, "User {}@{} attempted to login![ICP/UL]", bui.get(Constant.BUI_KEY_USER_NAME), ServletUtil.getClientIpAddr(request)); |
||||
sendFailedResponse(response); |
||||
QueuedJobs.getInstance().queue(()->{ |
||||
udao.updateLoginFailedCount((int)bui.get(Constant.BUI_KEY_USER_ID)); |
||||
int failedCount = (int) bui.get(Constant.BUI_KEY_FAIL_CNT); |
||||
failedCount++; |
||||
if(failedCount >= spdao.getInt(Constant.SP_MAX_LOGIN_FAIL_CNT, 5)) { |
||||
//lock account
|
||||
udao.lockUser((int)bui.get(Constant.BUI_KEY_USER_ID)); |
||||
} |
||||
}); |
||||
} |
||||
}else { |
||||
//User does not exist!
|
||||
log.info(mark, "User {}@{} attempted to login![UNE]", request.getParameter("username"), ServletUtil.getClientIpAddr(request)); |
||||
BCrypt.withDefaults().hashToString(spdao.getInt(Constant.SP_BCRYPT_COST, 12), request.getParameter("password").toCharArray()); |
||||
sendFailedResponse(response); |
||||
} |
||||
} |
||||
|
||||
private void sendFailedResponse(HttpServletResponse response) throws IOException{ |
||||
response.setContentType("application/json"); |
||||
JSONObject obj = new JSONObject(); |
||||
obj.put("status", "failed"); |
||||
obj.put("message", "Username and/or password incorrect, or account is being locked."); |
||||
obj.write(response.getWriter()); |
||||
} |
||||
|
||||
private void sendSuccessResponse(HttpServletResponse response) throws IOException{ |
||||
response.setContentType("application/json"); |
||||
JSONObject obj = new JSONObject(); |
||||
obj.put("status", "success"); |
||||
obj.write(response.getWriter()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,49 @@
|
||||
package org.leolo.web.dm.servlet; |
||||
|
||||
import java.io.IOException; |
||||
import javax.servlet.ServletException; |
||||
import javax.servlet.annotation.WebServlet; |
||||
import javax.servlet.http.HttpServletRequest; |
||||
import javax.servlet.http.HttpServletResponse; |
||||
|
||||
import org.json.JSONObject; |
||||
import org.leolo.web.dm.Constant; |
||||
import org.leolo.web.dm.dao.SystemParameterDao; |
||||
|
||||
/** |
||||
* Servlet implementation class UserInfoServlet |
||||
*/ |
||||
@WebServlet("/UserInfo") |
||||
public class UserInfoServlet extends BaseServlet { |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
/** |
||||
* @see BaseServlet#BaseServlet() |
||||
*/ |
||||
public UserInfoServlet() { |
||||
super(); |
||||
// TODO Auto-generated constructor stub
|
||||
} |
||||
|
||||
/** |
||||
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) |
||||
*/ |
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { |
||||
super.doGet(request, response); |
||||
if(this.fatalError) { |
||||
return; |
||||
} |
||||
response.setContentType("application/json"); |
||||
JSONObject obj = new JSONObject(); |
||||
obj.put("status", "success"); |
||||
obj.put("identified", this.userName!=null); |
||||
if(this.userName!=null) { |
||||
obj.put("username", this.userName); |
||||
obj.put("method", identifiedByKey?"api-key":"session"); |
||||
} |
||||
obj.put("system-name", new SystemParameterDao().getString(Constant.SP_SYSNAME)); |
||||
obj.put("api-version", Constant.SI_API_VERSION); |
||||
obj.write(response.getWriter()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,29 @@
|
||||
package org.leolo.web.dm.util; |
||||
|
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.ThreadFactory; |
||||
|
||||
import org.leolo.web.dm.Constant; |
||||
import org.leolo.web.dm.dao.SystemParameterDao; |
||||
|
||||
|
||||
public class QueuedJobs { |
||||
private static QueuedJobs instance; |
||||
private ExecutorService pool = Executors.newFixedThreadPool(new SystemParameterDao().getInt(Constant.SP_QUEUED_JOB_THREAD, 10)); |
||||
|
||||
public static synchronized QueuedJobs getInstance() { |
||||
if(instance==null) { |
||||
instance=new QueuedJobs(); |
||||
} |
||||
return instance; |
||||
} |
||||
|
||||
private QueuedJobs() { |
||||
|
||||
} |
||||
|
||||
public void queue(Runnable r) { |
||||
pool.execute(r); |
||||
} |
||||
} |
||||
@ -0,0 +1,25 @@
|
||||
package org.leolo.web.dm.util; |
||||
|
||||
import javax.servlet.http.HttpServletRequest; |
||||
|
||||
public class ServletUtil { |
||||
public static String getClientIpAddr(HttpServletRequest request) { |
||||
String ip = request.getHeader("X-Forwarded-For"); |
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("Proxy-Client-IP"); |
||||
} |
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("WL-Proxy-Client-IP"); |
||||
} |
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("HTTP_CLIENT_IP"); |
||||
} |
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getHeader("HTTP_X_FORWARDED_FOR"); |
||||
} |
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { |
||||
ip = request.getRemoteAddr(); |
||||
} |
||||
return ip; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue