diff --git a/pom.xml b/pom.xml index d874e04..20964be 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,11 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.security + spring-security-core + + org.mariadb.jdbc diff --git a/src/main/java/org/leolo/nrapi/Constants.java b/src/main/java/org/leolo/nrapi/Constants.java index a496b70..bc57423 100644 --- a/src/main/java/org/leolo/nrapi/Constants.java +++ b/src/main/java/org/leolo/nrapi/Constants.java @@ -2,4 +2,6 @@ package org.leolo.nrapi; public class Constants { public static final String REQ_ATTR_USER_ID = "auth-result-user-id"; + + public static final String SESSION_ATTR_USER_ID = "auth-result-user-id"; } diff --git a/src/main/java/org/leolo/nrapi/web/LoginAPI.java b/src/main/java/org/leolo/nrapi/web/LoginAPI.java index d9dd961..8ee7a68 100644 --- a/src/main/java/org/leolo/nrapi/web/LoginAPI.java +++ b/src/main/java/org/leolo/nrapi/web/LoginAPI.java @@ -1,14 +1,21 @@ package org.leolo.nrapi.web; +import org.leolo.nrapi.Constants; +import org.leolo.nrapi.manager.DatabaseManager; import org.leolo.nrapi.util.HttpReqRespUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; @RestController @RequestMapping(value = "web/auth") @@ -24,13 +31,68 @@ public class LoginAPI { ){ String reqIP = HttpReqRespUtils.getClientIpAddressIfServletRequestExist(); log.info("Login request from {}, username is {}, password length = {}", reqIP, userName, password.length()); - return new Object(){ - public String getStatus(){return "failed";} - public String getMessage() {return "Not implemented";} - }; + BCryptPasswordEncoder enc = new BCryptPasswordEncoder(); + boolean result = false; + try( + Connection conn = DatabaseManager.getInstance().getConnection(); + PreparedStatement pstmt = conn.prepareStatement("SELECT user_id, user_name, password FROM user WHERE user_name = ?"); + ){ + pstmt.setString(1, userName); + try(ResultSet rs = pstmt.executeQuery()){ + if(rs.next()){ + log.debug("User found!"); + String passwordHash = rs.getString("password"); + if(enc.matches(password, passwordHash)){ + //Login OK + result = true; + if(enc.upgradeEncoding(passwordHash)){ + log.info("User {} have old version of hash. Update required.", userName); + new Thread(()->{ + try( + Connection connection = DatabaseManager.getInstance().getConnection(); + PreparedStatement psUpd = connection.prepareStatement("UPDATE user SET password = ? WHERE user_name = ?"); + ){ + psUpd.setString(1, enc.encode(password)); + psUpd.setString(2, userName); + psUpd.executeUpdate(); + }catch (SQLException e){ + log.error(e.getMessage(), e); + } + }).start(); + } + session.setAttribute(Constants.SESSION_ATTR_USER_ID, rs.getString("user_id")); + }else{ + //Login failed + } + }else{ + log.debug("User not found!"); + //No such user + //Do a encode to avoid time attack? + enc.encode(password); + } + } + }catch(SQLException e){ + log.error(e.getMessage(), e); + return new Object(){ + public String getStatus(){return "500";} + public String getMessage() {return "Unable to connection to database";} + }; + } + if(result){ + return new Object(){ + public String getStatus(){return "200";} + public String getMessage() {return "Login Success!";} + }; + + }else{ + return new Object(){ + public String getStatus(){return "401";} + public String getMessage() {return "Username or password incorrect";} + }; + } } @RequestMapping(value = "logout") - public Object doLogin( + public Object doLogout( HttpSession session ){ session.invalidate();