Merge pull request #50 from Kitzanos/feature/GEPAFINBE-52
Managed Login Attempt
This commit is contained in:
7
pom.xml
7
pom.xml
@@ -212,6 +212,13 @@
|
|||||||
<version>8.0.5</version>
|
<version>8.0.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.springfox</groupId>
|
||||||
|
<artifactId>springfox-boot-starter</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
|
|||||||
@@ -225,6 +225,11 @@ public class GepafinConstant {
|
|||||||
public static final String DD_MM_YYYY = "dd/MM/yyyy";
|
public static final String DD_MM_YYYY = "dd/MM/yyyy";
|
||||||
|
|
||||||
public static final String DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY="dashboard.widget.fetched.successfully";
|
public static final String DASHBOARD_WIDGET_FETCHED_SUCCESSFULLY="dashboard.widget.fetched.successfully";
|
||||||
|
public static final Integer DEFAULT_PAGE_LIMIT = 1000;
|
||||||
|
public static final Integer DEFAULT_PAGE = 1;
|
||||||
|
public static final String ATTEMPT_DATE = "attemptDate";
|
||||||
|
public static final String LOGIN_ATTEMPTED_CREATED_SUCCESSFULLY="login_attempt_successfully_created";
|
||||||
|
public static final String GET_LOGIN_ATTEMPT_MSG="get_login_attempt_se_msg";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package net.gepafin.tendermanagement.dao;
|
||||||
|
|
||||||
|
import net.gepafin.tendermanagement.config.Translator;
|
||||||
|
import net.gepafin.tendermanagement.constants.GepafinConstant;
|
||||||
|
import net.gepafin.tendermanagement.entities.LoginAttemptEntity;
|
||||||
|
import net.gepafin.tendermanagement.model.response.LoginAttemptPageableResponseBean;
|
||||||
|
import net.gepafin.tendermanagement.repositories.LoginAttemptRepository;
|
||||||
|
import net.gepafin.tendermanagement.util.DateTimeUtil;
|
||||||
|
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class LoginAttemptDao {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
LoginAttemptRepository loginAttemptRepository;
|
||||||
|
|
||||||
|
public void createLoginAttempt(LoginAttemptEntity loginAttemptEntity) {
|
||||||
|
loginAttemptEntity.setAttemptDate(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
|
||||||
|
|
||||||
|
loginAttemptRepository.save(loginAttemptEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoginAttemptPageableResponseBean<List<LoginAttemptEntity>> getLoginAttemptsList(Integer pageNo, Integer pageLimit) {
|
||||||
|
if (pageLimit == null || pageLimit <= 0) {
|
||||||
|
pageLimit = GepafinConstant.DEFAULT_PAGE_LIMIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageNo == null || pageNo <= 0) {
|
||||||
|
pageNo = GepafinConstant.DEFAULT_PAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Page<LoginAttemptEntity> page = loginAttemptRepository.findAll(PageRequest.of(pageNo - 1, pageLimit, Sort.by(GepafinConstant.ATTEMPT_DATE).descending()));
|
||||||
|
List<LoginAttemptEntity> list = new ArrayList<>();
|
||||||
|
for (LoginAttemptEntity loginAttemptEntity : page.getContent()) {
|
||||||
|
list.add(loginAttemptEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginAttemptPageableResponseBean<List<LoginAttemptEntity>> pageableResponseBean = new LoginAttemptPageableResponseBean<>();
|
||||||
|
pageableResponseBean.setBody(list);
|
||||||
|
pageableResponseBean.setCurrentPage(page.getNumber() + 1);
|
||||||
|
pageableResponseBean.setTotalPages(page.getTotalPages());
|
||||||
|
pageableResponseBean.setTotalRecords(page.getTotalElements());
|
||||||
|
pageableResponseBean.setPageSize(page.getSize());
|
||||||
|
pageableResponseBean.setStatus(Status.SUCCESS);
|
||||||
|
pageableResponseBean.setMessage(Translator.toLocale(GepafinConstant.GET_LOGIN_ATTEMPT_MSG));
|
||||||
|
return pageableResponseBean;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -257,9 +257,9 @@ public class UserDao {
|
|||||||
log.info("User deleted with ID: {}", id);
|
log.info("User deleted with ID: {}", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JWTToken login(LoginReq loginReq) {
|
public JWTToken login(LoginReq loginReq,HttpServletRequest request) {
|
||||||
log.info("User login attempt for email: {}", loginReq.getEmail());
|
log.info("User login attempt for email: {}", loginReq.getEmail());
|
||||||
JWTToken jwtToken = authService.login(loginReq);
|
JWTToken jwtToken = authService.login(loginReq,request);
|
||||||
log.info("Login successful for email: {}", loginReq.getEmail());
|
log.info("Login successful for email: {}", loginReq.getEmail());
|
||||||
return jwtToken;
|
return jwtToken;
|
||||||
}
|
}
|
||||||
@@ -354,4 +354,5 @@ public class UserDao {
|
|||||||
return authService.validateNewUserToken(token);
|
return authService.validateNewUserToken(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package net.gepafin.tendermanagement.entities;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "LOGIN_ATTEMPT")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class LoginAttemptEntity {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
@Column(name = "ID", unique = true)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(name = "USERNAME")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Column(name = "USER_ID")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@Column(name = "ATTEMPT_DATE", nullable = false)
|
||||||
|
private LocalDateTime attemptDate;
|
||||||
|
|
||||||
|
@Column(name = "IP_ADDRESS", length = 100)
|
||||||
|
private String ipAddress;
|
||||||
|
|
||||||
|
@Column(name = "USER_AGENT")
|
||||||
|
private String userAgent;
|
||||||
|
|
||||||
|
@Column(name = "RESULT", length = 100, nullable = false)
|
||||||
|
private String result;
|
||||||
|
|
||||||
|
@Column(name = "ERROR_MSG")
|
||||||
|
private String errorMsg;
|
||||||
|
|
||||||
|
@Column(name = "ATTEMPT_TYPE", length = 100, nullable = false)
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package net.gepafin.tendermanagement.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
|
||||||
|
public enum LoginAttemptResultEnum {
|
||||||
|
|
||||||
|
SUCCESS("SUCCESS"),
|
||||||
|
FAILED("FAILED");
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
LoginAttemptResultEnum(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.valueOf(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package net.gepafin.tendermanagement.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
|
||||||
|
public enum LoginAttemptTypeEnum {
|
||||||
|
|
||||||
|
LOGIN("LOGIN"),
|
||||||
|
SWITCH("SWITCH");
|
||||||
|
|
||||||
|
private String value;
|
||||||
|
|
||||||
|
LoginAttemptTypeEnum(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonValue
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.valueOf(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package net.gepafin.tendermanagement.model.request;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class LoginAttemptReq {
|
||||||
|
|
||||||
|
private String userName;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Long userId;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package net.gepafin.tendermanagement.model.response;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class LoginAttemptPageableResponseBean<T> implements Serializable {
|
||||||
|
|
||||||
|
private transient T body;
|
||||||
|
|
||||||
|
private Long totalRecords;
|
||||||
|
|
||||||
|
private int currentPage;
|
||||||
|
|
||||||
|
private int totalPages;
|
||||||
|
|
||||||
|
private int pageSize;
|
||||||
|
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package net.gepafin.tendermanagement.repositories;
|
||||||
|
|
||||||
|
import net.gepafin.tendermanagement.entities.LoginAttemptEntity;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public interface LoginAttemptRepository extends JpaRepository<LoginAttemptEntity,Long> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package net.gepafin.tendermanagement.service;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import net.gepafin.tendermanagement.entities.LoginAttemptEntity;
|
||||||
|
import net.gepafin.tendermanagement.model.request.LoginAttemptReq;
|
||||||
|
import net.gepafin.tendermanagement.model.response.LoginAttemptPageableResponseBean;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface LoginAttemptService {
|
||||||
|
|
||||||
|
LoginAttemptPageableResponseBean<List<LoginAttemptEntity>> getLoginAttemptsList(Integer pageNo, Integer pageLimit);
|
||||||
|
|
||||||
|
void createLoginAttempt(LoginAttemptReq loginAttemptReq, HttpServletRequest request);
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ public interface UserService {
|
|||||||
|
|
||||||
void deleteUser(Long userId);
|
void deleteUser(Long userId);
|
||||||
|
|
||||||
JWTToken login(LoginReq loginReq);
|
JWTToken login(LoginReq loginReq,HttpServletRequest request);
|
||||||
|
|
||||||
UserEntity validateUser(Long userId);
|
UserEntity validateUser(Long userId);
|
||||||
|
|
||||||
@@ -41,4 +41,7 @@ public interface UserService {
|
|||||||
|
|
||||||
UserSamlResponse validateNewUserToken(HttpServletRequest request, String token);
|
UserSamlResponse validateNewUserToken(HttpServletRequest request, String token);
|
||||||
UserEntity getUserByBeneficiaryId(Long beneficiaryId);
|
UserEntity getUserByBeneficiaryId(Long beneficiaryId);
|
||||||
|
|
||||||
|
public UserEntity getUserEntityById(Long userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,13 @@ import net.gepafin.tendermanagement.config.Translator;
|
|||||||
import net.gepafin.tendermanagement.config.jwt.TokenProvider;
|
import net.gepafin.tendermanagement.config.jwt.TokenProvider;
|
||||||
import net.gepafin.tendermanagement.constants.GepafinConstant;
|
import net.gepafin.tendermanagement.constants.GepafinConstant;
|
||||||
import net.gepafin.tendermanagement.dao.CompanyDao;
|
import net.gepafin.tendermanagement.dao.CompanyDao;
|
||||||
|
import net.gepafin.tendermanagement.dao.LoginAttemptDao;
|
||||||
import net.gepafin.tendermanagement.dao.RoleDao;
|
import net.gepafin.tendermanagement.dao.RoleDao;
|
||||||
|
import net.gepafin.tendermanagement.entities.LoginAttemptEntity;
|
||||||
import net.gepafin.tendermanagement.entities.SamlResponseEntity;
|
import net.gepafin.tendermanagement.entities.SamlResponseEntity;
|
||||||
import net.gepafin.tendermanagement.entities.UserEntity;
|
import net.gepafin.tendermanagement.entities.UserEntity;
|
||||||
|
import net.gepafin.tendermanagement.enums.LoginAttemptResultEnum;
|
||||||
|
import net.gepafin.tendermanagement.enums.LoginAttemptTypeEnum;
|
||||||
import net.gepafin.tendermanagement.enums.UserStatusEnum;
|
import net.gepafin.tendermanagement.enums.UserStatusEnum;
|
||||||
import net.gepafin.tendermanagement.model.request.LoginReq;
|
import net.gepafin.tendermanagement.model.request.LoginReq;
|
||||||
import net.gepafin.tendermanagement.model.response.CompanyResponse;
|
import net.gepafin.tendermanagement.model.response.CompanyResponse;
|
||||||
@@ -57,29 +61,61 @@ public class AuthenticationService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SamlResponseRepository samlResponseLogRepository;
|
private SamlResponseRepository samlResponseLogRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LoginAttemptDao loginAttemptDao;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public AuthenticationService(TokenProvider tokenProvider, AuthenticationManager authenticationManager) {
|
public AuthenticationService(TokenProvider tokenProvider, AuthenticationManager authenticationManager) {
|
||||||
this.tokenProvider = tokenProvider;
|
this.tokenProvider = tokenProvider;
|
||||||
this.authenticationManager = authenticationManager;
|
this.authenticationManager = authenticationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JWTToken login(LoginReq loginReq) {
|
public JWTToken login(LoginReq loginReq,HttpServletRequest request) {
|
||||||
|
UserEntity user=null;
|
||||||
|
try {
|
||||||
|
LoginAttemptEntity loginAttemptEntity = prepareLoginAttemptEntity(loginReq, request);
|
||||||
log.info("Attempting login for email: {}", loginReq.getEmail());
|
log.info("Attempting login for email: {}", loginReq.getEmail());
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
|
||||||
loginReq.getEmail(), loginReq.getPassword());
|
loginReq.getEmail(), loginReq.getPassword());
|
||||||
Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
|
Authentication authentication = this.authenticationManager.authenticate(authenticationToken);
|
||||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||||
log.info("Authentication successful for email: {}", loginReq.getEmail());
|
log.info("Authentication successful for email: {}", loginReq.getEmail());
|
||||||
UserEntity user = userRepository.findByEmailIgnoreCase(loginReq.getEmail())
|
user = userRepository.findByEmailIgnoreCase(loginReq.getEmail())
|
||||||
.orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND,
|
.orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND,
|
||||||
Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)));
|
Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)));
|
||||||
|
loginAttemptEntity.setUserId(user.getId());
|
||||||
if (Boolean.FALSE.equals(UserStatusEnum.ACTIVE.getValue().equals(user.getStatus()))) {
|
if (Boolean.FALSE.equals(UserStatusEnum.ACTIVE.getValue().equals(user.getStatus()))) {
|
||||||
throw new ResourceNotFoundException(Status.NOT_FOUND,
|
throw new ResourceNotFoundException(Status.NOT_FOUND,
|
||||||
Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG));
|
Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG));
|
||||||
|
}
|
||||||
|
createSuccessLoginAttempt(loginAttemptEntity);
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return getJWTTokenBean(user, loginReq.getRememberMe());
|
return getJWTTokenBean(user, loginReq.getRememberMe());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LoginAttemptEntity prepareLoginAttemptEntity(LoginReq loginUserReq, HttpServletRequest request) {
|
||||||
|
String ipAddress = Utils.getClientIpAddress(request);
|
||||||
|
String userAgent = request.getHeader("user-agent");
|
||||||
|
LoginAttemptEntity loginAttemptEntity = new LoginAttemptEntity();
|
||||||
|
loginAttemptEntity.setType(LoginAttemptTypeEnum.LOGIN.getValue());
|
||||||
|
loginAttemptEntity.setUsername(loginUserReq.getEmail());
|
||||||
|
loginAttemptEntity.setIpAddress(ipAddress);
|
||||||
|
loginAttemptEntity.setUserAgent(userAgent);
|
||||||
|
return loginAttemptEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSuccessLoginAttempt(LoginAttemptEntity loginAttemptEntity) {
|
||||||
|
loginAttemptEntity.setResult(LoginAttemptResultEnum.SUCCESS.getValue());
|
||||||
|
loginAttemptDao.createLoginAttempt(loginAttemptEntity);
|
||||||
|
}
|
||||||
|
private void createFailedLoginAttempt(LoginAttemptEntity loginAttemptEntity, String errorMsg) {
|
||||||
|
loginAttemptEntity.setResult(LoginAttemptResultEnum.FAILED.getValue());
|
||||||
|
loginAttemptEntity.setErrorMsg(errorMsg);
|
||||||
|
loginAttemptDao.createLoginAttempt(loginAttemptEntity);
|
||||||
|
}
|
||||||
public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe) {
|
public JWTToken getJWTTokenBean(UserEntity user, Boolean rememberMe) {
|
||||||
user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
|
user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now()));
|
||||||
userRepository.save(user);
|
userRepository.save(user);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package net.gepafin.tendermanagement.service.impl;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import net.gepafin.tendermanagement.dao.LoginAttemptDao;
|
||||||
|
import net.gepafin.tendermanagement.entities.LoginAttemptEntity;
|
||||||
|
import net.gepafin.tendermanagement.enums.LoginAttemptResultEnum;
|
||||||
|
import net.gepafin.tendermanagement.enums.LoginAttemptTypeEnum;
|
||||||
|
import net.gepafin.tendermanagement.model.request.LoginAttemptReq;
|
||||||
|
import net.gepafin.tendermanagement.model.response.LoginAttemptPageableResponseBean;
|
||||||
|
import net.gepafin.tendermanagement.service.LoginAttemptService;
|
||||||
|
import net.gepafin.tendermanagement.util.Utils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class LoginAttemptServiceImpl implements LoginAttemptService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
LoginAttemptDao loginAttemptDao;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LoginAttemptPageableResponseBean<List<LoginAttemptEntity>> getLoginAttemptsList(Integer pageNo, Integer pageLimit) {
|
||||||
|
return loginAttemptDao.getLoginAttemptsList(pageNo, pageLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createLoginAttempt(LoginAttemptReq loginAttemptReq, HttpServletRequest request) {
|
||||||
|
String ipAddress = Utils.getClientIpAddress(request);
|
||||||
|
String userAgent = request.getHeader("user-agent");
|
||||||
|
LoginAttemptEntity loginAttemptEntity = new LoginAttemptEntity();
|
||||||
|
loginAttemptEntity.setType(LoginAttemptTypeEnum.SWITCH.getValue());
|
||||||
|
loginAttemptEntity.setIpAddress(ipAddress);
|
||||||
|
loginAttemptEntity.setUserAgent(userAgent);
|
||||||
|
loginAttemptEntity.setUsername(loginAttemptReq.getUserName());
|
||||||
|
loginAttemptEntity.setResult(LoginAttemptResultEnum.SUCCESS.getValue());
|
||||||
|
loginAttemptDao.createLoginAttempt(loginAttemptEntity);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,8 +66,8 @@ public class UserServiceImpl implements UserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JWTToken login(LoginReq loginReq) {
|
public JWTToken login(LoginReq loginReq,HttpServletRequest request) {
|
||||||
return userDao.login(loginReq);
|
return userDao.login(loginReq,request);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,4 +119,9 @@ public class UserServiceImpl implements UserService {
|
|||||||
public UserEntity getUserByBeneficiaryId(Long beneficiaryId) {
|
public UserEntity getUserByBeneficiaryId(Long beneficiaryId) {
|
||||||
return userDao.getUserByBeneficiaryId(beneficiaryId);
|
return userDao.getUserByBeneficiaryId(beneficiaryId);
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public UserEntity getUserEntityById(Long userId) {
|
||||||
|
// Calling DAO Function
|
||||||
|
return userDao.validateUser(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,15 +4,13 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Base64;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.apache.commons.collections4.MapUtils;
|
import org.apache.commons.collections4.MapUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -302,5 +300,12 @@ public class Utils {
|
|||||||
private static String replaceNull(String text, String target, String replacement) {
|
private static String replaceNull(String text, String target, String replacement) {
|
||||||
return text.replace(target, replacement != null ? replacement : "");
|
return text.replace(target, replacement != null ? replacement : "");
|
||||||
}
|
}
|
||||||
|
public static String getClientIpAddress(HttpServletRequest request) {
|
||||||
|
String header = request.getHeader("X-Forwarded-For");
|
||||||
|
if (org.apache.commons.lang3.StringUtils.isBlank(header)) {
|
||||||
|
return request.getRemoteAddr();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StringTokenizer(header, ",").nextToken().trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package net.gepafin.tendermanagement.web.rest.api;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
|
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
||||||
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import io.swagger.annotations.ApiParam;
|
||||||
|
import net.gepafin.tendermanagement.entities.LoginAttemptEntity;
|
||||||
|
import net.gepafin.tendermanagement.model.request.LoginAttemptReq;
|
||||||
|
import net.gepafin.tendermanagement.model.response.LoginAttemptPageableResponseBean;
|
||||||
|
import net.gepafin.tendermanagement.model.util.Response;
|
||||||
|
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Validated
|
||||||
|
public interface LoginAttemptApi {
|
||||||
|
|
||||||
|
default Optional<NativeWebRequest> getRequest() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Api to get list of login attempts", responses = {
|
||||||
|
@ApiResponse(responseCode = "200", description = "OK"),
|
||||||
|
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
|
||||||
|
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE)})),
|
||||||
|
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
|
||||||
|
@ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE)}))})
|
||||||
|
@GetMapping(value = "/login-attempt", produces = {"application/json"})
|
||||||
|
@PreAuthorize("hasRole('ROLE_SUPER_ADMIN')")
|
||||||
|
default ResponseEntity<LoginAttemptPageableResponseBean<List<LoginAttemptEntity>>> getLoginAttemptsList(
|
||||||
|
@ApiParam(value = "page number") @RequestParam(name = "pageNo", required = false) Integer pageNo,
|
||||||
|
@ApiParam(value = "page limit") @RequestParam(name = "pageLimit", required = false) Integer pageLimit) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "Api to create a login attempt", responses = {
|
||||||
|
@ApiResponse(responseCode = "201", description = "Created"),
|
||||||
|
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
|
||||||
|
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE)})),
|
||||||
|
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
|
||||||
|
@ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE)}))})
|
||||||
|
@PostMapping(value = "/login-attempt", consumes = {"application/json"})
|
||||||
|
default ResponseEntity<Response<Void>> createLoginAttempt(@ApiParam(value = "login attempt request", required = true) @Valid @RequestBody LoginAttemptReq loginAttemptReq, HttpServletRequest request) {
|
||||||
|
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package net.gepafin.tendermanagement.web.rest.api;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.media.Content;
|
|
||||||
import io.swagger.v3.oas.annotations.media.ExampleObject;
|
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import net.gepafin.tendermanagement.web.rest.api.errors.ErrorConstants;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
|
|
||||||
@Validated
|
|
||||||
public interface PdfApi {
|
|
||||||
|
|
||||||
@Operation(summary = "API to generate PDF for an application",
|
|
||||||
responses = {
|
|
||||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = "application/pdf")),
|
|
||||||
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
|
|
||||||
@ExampleObject(value = ErrorConstants.NOTFOUND_ERROR_EXAMPLE) })),
|
|
||||||
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
|
|
||||||
@ExampleObject(value = ErrorConstants.UNAUTHORIZED_ERROR_EXAMPLE) })),
|
|
||||||
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, examples = {
|
|
||||||
@ExampleObject(value = ErrorConstants.BADREQUEST_ERROR_EXAMPLE) }))
|
|
||||||
})
|
|
||||||
@PostMapping(value = "/{applicationId}/generate-pdf",
|
|
||||||
produces = { "application/pdf" })
|
|
||||||
public ResponseEntity<byte[]> generateApplicationPdf(
|
|
||||||
HttpServletRequest request,
|
|
||||||
@Parameter(description = "The application id", required = true)
|
|
||||||
@PathVariable(value = "applicationId", required = true) Long applicationId);
|
|
||||||
}
|
|
||||||
@@ -104,7 +104,7 @@ public interface UserApi {
|
|||||||
@RequestMapping(value = "/login",
|
@RequestMapping(value = "/login",
|
||||||
produces = {"application/json"},
|
produces = {"application/json"},
|
||||||
method = RequestMethod.POST)
|
method = RequestMethod.POST)
|
||||||
ResponseEntity<Response<JWTToken>> login(
|
ResponseEntity<Response<JWTToken>> login(HttpServletRequest request,
|
||||||
@Parameter(description = "Login request object", required = true) @Valid @RequestBody LoginReq loginReq);
|
@Parameter(description = "Login request object", required = true) @Valid @RequestBody LoginReq loginReq);
|
||||||
@Operation(summary = "Api to initiate password reset request",
|
@Operation(summary = "Api to initiate password reset request",
|
||||||
responses = {
|
responses = {
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package net.gepafin.tendermanagement.web.rest.api.impl;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import net.gepafin.tendermanagement.config.Translator;
|
||||||
|
import net.gepafin.tendermanagement.constants.GepafinConstant;
|
||||||
|
import net.gepafin.tendermanagement.entities.LoginAttemptEntity;
|
||||||
|
import net.gepafin.tendermanagement.entities.UserEntity;
|
||||||
|
import net.gepafin.tendermanagement.model.request.LoginAttemptReq;
|
||||||
|
import net.gepafin.tendermanagement.model.response.LoginAttemptPageableResponseBean;
|
||||||
|
import net.gepafin.tendermanagement.model.util.Response;
|
||||||
|
import net.gepafin.tendermanagement.service.LoginAttemptService;
|
||||||
|
import net.gepafin.tendermanagement.service.UserService;
|
||||||
|
import net.gepafin.tendermanagement.util.Validator;
|
||||||
|
import net.gepafin.tendermanagement.web.rest.api.LoginAttemptApi;
|
||||||
|
import net.gepafin.tendermanagement.web.rest.api.errors.Status;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("${openapi.gepafin.base-path:/v1/loginAttempt}")
|
||||||
|
public class LoginAttemptApiController implements LoginAttemptApi {
|
||||||
|
|
||||||
|
public final Logger log = LoggerFactory.getLogger(LoginAttemptApiController.class);
|
||||||
|
@Autowired
|
||||||
|
Validator validator;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private LoginAttemptService loginAttemptService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<LoginAttemptPageableResponseBean<List<LoginAttemptEntity>>> getLoginAttemptsList(Integer pageNo, Integer pageLimit) {
|
||||||
|
LoginAttemptPageableResponseBean<List<LoginAttemptEntity>> response = loginAttemptService.getLoginAttemptsList(pageNo, pageLimit);
|
||||||
|
return ResponseEntity.status(HttpStatus.OK).body(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResponseEntity<Response<Void>> createLoginAttempt(LoginAttemptReq loginAttemptReq, HttpServletRequest request) {
|
||||||
|
Map<String, Object> userInfo = validator.getUserInfoFromToken(request);
|
||||||
|
String userIdString = (String) userInfo.get("userId");
|
||||||
|
UserEntity currentUser = userService.getUserEntityById(Long.parseLong(userIdString));
|
||||||
|
loginAttemptReq.setUserName(currentUser.getEmail());
|
||||||
|
loginAttemptService.createLoginAttempt(loginAttemptReq, request);
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(new Response<Void>(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.LOGIN_ATTEMPTED_CREATED_SUCCESSFULLY)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
package net.gepafin.tendermanagement.web.rest.api.impl;
|
|
||||||
|
|
||||||
import com.itextpdf.text.*;
|
|
||||||
import com.itextpdf.text.pdf.*;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import net.gepafin.tendermanagement.dao.RoundedCorners;
|
|
||||||
import net.gepafin.tendermanagement.service.PdfService;
|
|
||||||
import net.gepafin.tendermanagement.web.rest.api.PdfApi;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
|
|
||||||
@RestController
|
|
||||||
public class PdfController implements PdfApi {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private PdfService pdfService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ResponseEntity<byte[]> generateApplicationPdf(HttpServletRequest request, Long applicationId) {
|
|
||||||
byte[] pdfBytes =pdfService.generatePdf(request,applicationId);
|
|
||||||
|
|
||||||
// Prepare headers for downloading the PDF
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.add("Content-Disposition", "attachment; filename=bando-preview.pdf");
|
|
||||||
|
|
||||||
// Return the PDF as a response
|
|
||||||
return ResponseEntity.ok()
|
|
||||||
.headers(headers)
|
|
||||||
.contentType(MediaType.APPLICATION_PDF)
|
|
||||||
.body(pdfBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -70,10 +70,10 @@ public class UserApiController implements UserApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<Response<JWTToken>> login(
|
public ResponseEntity<Response<JWTToken>> login(HttpServletRequest request,
|
||||||
@Valid @RequestBody LoginReq loginReq) {
|
@Valid @RequestBody LoginReq loginReq) {
|
||||||
log.info("User login attempt ");
|
log.info("User login attempt ");
|
||||||
JWTToken jwtToken = userService.login(loginReq);
|
JWTToken jwtToken = userService.login(loginReq,request);
|
||||||
return ResponseEntity.ok(new Response<>(jwtToken, Status.SUCCESS, Translator.toLocale(GepafinConstant.LOGIN_SUCCESS_MSG)));
|
return ResponseEntity.ok(new Response<>(jwtToken, Status.SUCCESS, Translator.toLocale(GepafinConstant.LOGIN_SUCCESS_MSG)));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1051,6 +1051,38 @@
|
|||||||
<sqlFile dbms="postgresql"
|
<sqlFile dbms="postgresql"
|
||||||
path="db/dump/update_system_email_template_of_application_submission.sql" />
|
path="db/dump/update_system_email_template_of_application_submission.sql" />
|
||||||
</changeSet>
|
</changeSet>
|
||||||
|
|
||||||
|
<changeSet id="15-10-2024_2" author="Nisha Kashyap">
|
||||||
|
<preConditions onFail="MARK_RAN">
|
||||||
|
<not>
|
||||||
|
<tableExists tableName="login_attempt" />
|
||||||
|
</not>
|
||||||
|
</preConditions>
|
||||||
|
<createTable tableName="login_attempt">
|
||||||
|
<column autoIncrement="true" name="id" type="INTEGER">
|
||||||
|
<constraints nullable="false" primaryKey="true"
|
||||||
|
primaryKeyName="login_attempt_pkey" />
|
||||||
|
</column>
|
||||||
|
<column name="username" type="VARCHAR(255)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="user_id" type="INTEGER" />
|
||||||
|
<column name="attempt_date" type="TIMESTAMP WITHOUT TIME ZONE" >
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="ip_address" type="VARCHAR(100)" />
|
||||||
|
<column name="user_agent" type="VARCHAR(255)" />
|
||||||
|
<column name="result" type="VARCHAR(100)">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="attempt_type" type="VARCHAR(100)" defaultValue="LOGIN">
|
||||||
|
<constraints nullable="false"/>
|
||||||
|
</column>
|
||||||
|
<column name="error_msg" type="VARCHAR(255)" />
|
||||||
|
</createTable>
|
||||||
|
</changeSet>
|
||||||
|
|
||||||
|
|
||||||
<changeSet id="15-10-2024_1" author="Harish Bagora">
|
<changeSet id="15-10-2024_1" author="Harish Bagora">
|
||||||
<insert tableName="gepafin_user">
|
<insert tableName="gepafin_user">
|
||||||
<column name="password" value="$2a$10$doUyOcEm8WPuFfpFT5y18.1DvZzF7exbqgy9X0P27cUBK7YWbfzzS"/>
|
<column name="password" value="$2a$10$doUyOcEm8WPuFfpFT5y18.1DvZzF7exbqgy9X0P27cUBK7YWbfzzS"/>
|
||||||
|
|||||||
@@ -248,5 +248,7 @@ application.signed.document.not.found=Signed document for the application not fo
|
|||||||
delete.signed.document.file.success=Signed document deleted successfully.
|
delete.signed.document.file.success=Signed document deleted successfully.
|
||||||
|
|
||||||
dashboard.widget.fetched.successfully=Dasboard widget fetched sucessfully.
|
dashboard.widget.fetched.successfully=Dasboard widget fetched sucessfully.
|
||||||
|
login_attempt_successfully_created = Login attempt successfully created.
|
||||||
|
get_login_attempt_se_msg=Login attempts fetched successfully.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -244,4 +244,6 @@ application.signed.document.not.found=Documento firmato per l'applicazione non t
|
|||||||
delete.signed.document.file.success=Documento firmato eliminato con successo.
|
delete.signed.document.file.success=Documento firmato eliminato con successo.
|
||||||
|
|
||||||
dashboard.widget.fetched.successfully=Widget dashboard recuperato correttamente.
|
dashboard.widget.fetched.successfully=Widget dashboard recuperato correttamente.
|
||||||
|
login_attempt_successfully_created= Tentativo di login creato con successo.
|
||||||
|
get_login_attempt_se_msg=Lista dei tentativi di accesso recuperata correttamente.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user