From e896c6ab1be8c5e7515b3d449b7f8add3271ab00 Mon Sep 17 00:00:00 2001 From: nisha Date: Tue, 15 Oct 2024 18:05:14 +0530 Subject: [PATCH] Done ticket GEPAFINBE-52 --- pom.xml | 7 ++ .../constants/GepafinConstant.java | 5 ++ .../tendermanagement/dao/LoginAttemptDao.java | 57 +++++++++++++++++ .../gepafin/tendermanagement/dao/UserDao.java | 5 +- .../entities/LoginAttemptEntity.java | 44 +++++++++++++ .../enums/LoginAttemptResultEnum.java | 25 ++++++++ .../enums/LoginAttemptTypeEnum.java | 25 ++++++++ .../model/request/LoginAttemptReq.java | 18 ++++++ .../LoginAttemptPageableResponseBean.java | 38 +++++++++++ .../repositories/LoginAttemptRepository.java | 9 +++ .../service/LoginAttemptService.java | 15 +++++ .../tendermanagement/service/UserService.java | 5 +- .../service/impl/AuthenticationService.java | 64 +++++++++++++++---- .../service/impl/LoginAttemptServiceImpl.java | 40 ++++++++++++ .../service/impl/UserServiceImpl.java | 9 ++- .../gepafin/tendermanagement/util/Utils.java | 13 ++-- .../web/rest/api/LoginAttemptApi.java | 60 +++++++++++++++++ .../tendermanagement/web/rest/api/PdfApi.java | 35 ---------- .../web/rest/api/UserApi.java | 2 +- .../api/impl/LoginAttemptApiController.java | 56 ++++++++++++++++ .../web/rest/api/impl/PdfController.java | 40 ------------ .../web/rest/api/impl/UserApiController.java | 4 +- .../db/changelog/db.changelog-1.0.0.xml | 31 +++++++++ src/main/resources/message_en.properties | 2 + src/main/resources/message_it.properties | 2 + 25 files changed, 510 insertions(+), 101 deletions(-) create mode 100644 src/main/java/net/gepafin/tendermanagement/dao/LoginAttemptDao.java create mode 100644 src/main/java/net/gepafin/tendermanagement/entities/LoginAttemptEntity.java create mode 100644 src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptResultEnum.java create mode 100644 src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptTypeEnum.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/request/LoginAttemptReq.java create mode 100644 src/main/java/net/gepafin/tendermanagement/model/response/LoginAttemptPageableResponseBean.java create mode 100644 src/main/java/net/gepafin/tendermanagement/repositories/LoginAttemptRepository.java create mode 100644 src/main/java/net/gepafin/tendermanagement/service/LoginAttemptService.java create mode 100644 src/main/java/net/gepafin/tendermanagement/service/impl/LoginAttemptServiceImpl.java create mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/LoginAttemptApi.java delete mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/PdfApi.java create mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/LoginAttemptApiController.java delete mode 100644 src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PdfController.java diff --git a/pom.xml b/pom.xml index 1e6d394a..b443ec18 100644 --- a/pom.xml +++ b/pom.xml @@ -212,6 +212,13 @@ 8.0.5 + + io.springfox + springfox-boot-starter + 3.0.0 + + + diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index c21cceaf..49a49126 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -225,6 +225,11 @@ public class GepafinConstant { 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 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"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/LoginAttemptDao.java b/src/main/java/net/gepafin/tendermanagement/dao/LoginAttemptDao.java new file mode 100644 index 00000000..509d4843 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/dao/LoginAttemptDao.java @@ -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> 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 page = loginAttemptRepository.findAll(PageRequest.of(pageNo - 1, pageLimit, Sort.by(GepafinConstant.ATTEMPT_DATE).descending())); + List list = new ArrayList<>(); + for (LoginAttemptEntity loginAttemptEntity : page.getContent()) { + list.add(loginAttemptEntity); + } + + LoginAttemptPageableResponseBean> 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; + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java index 84440b5f..a796114a 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/UserDao.java @@ -257,9 +257,9 @@ public class UserDao { 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()); - JWTToken jwtToken = authService.login(loginReq); + JWTToken jwtToken = authService.login(loginReq,request); log.info("Login successful for email: {}", loginReq.getEmail()); return jwtToken; } @@ -354,4 +354,5 @@ public class UserDao { return authService.validateNewUserToken(token); } + } diff --git a/src/main/java/net/gepafin/tendermanagement/entities/LoginAttemptEntity.java b/src/main/java/net/gepafin/tendermanagement/entities/LoginAttemptEntity.java new file mode 100644 index 00000000..11fe1a99 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/entities/LoginAttemptEntity.java @@ -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; + +} diff --git a/src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptResultEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptResultEnum.java new file mode 100644 index 00000000..bd039eb5 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptResultEnum.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptTypeEnum.java b/src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptTypeEnum.java new file mode 100644 index 00000000..dc597e13 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/enums/LoginAttemptTypeEnum.java @@ -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); + } +} \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/LoginAttemptReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/LoginAttemptReq.java new file mode 100644 index 00000000..f7a48ad3 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/request/LoginAttemptReq.java @@ -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; +} + diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/LoginAttemptPageableResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/LoginAttemptPageableResponseBean.java new file mode 100644 index 00000000..d28d1fd2 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/model/response/LoginAttemptPageableResponseBean.java @@ -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 implements Serializable { + + private transient T body; + + private Long totalRecords; + + private int currentPage; + + private int totalPages; + + private int pageSize; + + private Status status; + + private String message; + +} + + + + + + + + + + + diff --git a/src/main/java/net/gepafin/tendermanagement/repositories/LoginAttemptRepository.java b/src/main/java/net/gepafin/tendermanagement/repositories/LoginAttemptRepository.java new file mode 100644 index 00000000..257b8ed8 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/repositories/LoginAttemptRepository.java @@ -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 { +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/LoginAttemptService.java b/src/main/java/net/gepafin/tendermanagement/service/LoginAttemptService.java new file mode 100644 index 00000000..3e4ed31a --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/LoginAttemptService.java @@ -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> getLoginAttemptsList(Integer pageNo, Integer pageLimit); + + void createLoginAttempt(LoginAttemptReq loginAttemptReq, HttpServletRequest request); +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/UserService.java b/src/main/java/net/gepafin/tendermanagement/service/UserService.java index 47116eed..b9fc2072 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/UserService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/UserService.java @@ -21,7 +21,7 @@ public interface UserService { void deleteUser(Long userId); - JWTToken login(LoginReq loginReq); + JWTToken login(LoginReq loginReq,HttpServletRequest request); UserEntity validateUser(Long userId); @@ -41,4 +41,7 @@ public interface UserService { UserSamlResponse validateNewUserToken(HttpServletRequest request, String token); UserEntity getUserByBeneficiaryId(Long beneficiaryId); + + public UserEntity getUserEntityById(Long userId); + } diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java index 4153c2f2..1cb87645 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/AuthenticationService.java @@ -6,9 +6,13 @@ import net.gepafin.tendermanagement.config.Translator; import net.gepafin.tendermanagement.config.jwt.TokenProvider; import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.dao.CompanyDao; +import net.gepafin.tendermanagement.dao.LoginAttemptDao; import net.gepafin.tendermanagement.dao.RoleDao; +import net.gepafin.tendermanagement.entities.LoginAttemptEntity; import net.gepafin.tendermanagement.entities.SamlResponseEntity; 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.model.request.LoginReq; import net.gepafin.tendermanagement.model.response.CompanyResponse; @@ -57,29 +61,61 @@ public class AuthenticationService { @Autowired private SamlResponseRepository samlResponseLogRepository; + @Autowired + private LoginAttemptDao loginAttemptDao; + @Autowired public AuthenticationService(TokenProvider tokenProvider, AuthenticationManager authenticationManager) { this.tokenProvider = tokenProvider; this.authenticationManager = authenticationManager; } - public JWTToken login(LoginReq loginReq) { - log.info("Attempting login for email: {}", loginReq.getEmail()); - UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( - loginReq.getEmail(), loginReq.getPassword()); - Authentication authentication = this.authenticationManager.authenticate(authenticationToken); - SecurityContextHolder.getContext().setAuthentication(authentication); - log.info("Authentication successful for email: {}", loginReq.getEmail()); - UserEntity user = userRepository.findByEmailIgnoreCase(loginReq.getEmail()) - .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG))); - if (Boolean.FALSE.equals(UserStatusEnum.ACTIVE.getValue().equals(user.getStatus()))) { - throw new ResourceNotFoundException(Status.NOT_FOUND, - Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)); + public JWTToken login(LoginReq loginReq,HttpServletRequest request) { + UserEntity user=null; + try { + LoginAttemptEntity loginAttemptEntity = prepareLoginAttemptEntity(loginReq, request); + log.info("Attempting login for email: {}", loginReq.getEmail()); + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( + loginReq.getEmail(), loginReq.getPassword()); + Authentication authentication = this.authenticationManager.authenticate(authenticationToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + log.info("Authentication successful for email: {}", loginReq.getEmail()); + user = userRepository.findByEmailIgnoreCase(loginReq.getEmail()) + .orElseThrow(() -> new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG))); + loginAttemptEntity.setUserId(user.getId()); + if (Boolean.FALSE.equals(UserStatusEnum.ACTIVE.getValue().equals(user.getStatus()))) { + throw new ResourceNotFoundException(Status.NOT_FOUND, + Translator.toLocale(GepafinConstant.USER_NOT_FOUND_MSG)); + } + createSuccessLoginAttempt(loginAttemptEntity); + } catch (Exception e) { + + } 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) { user.setLastLogin(DateTimeUtil.DateServerToUTC(LocalDateTime.now())); userRepository.save(user); diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/LoginAttemptServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/LoginAttemptServiceImpl.java new file mode 100644 index 00000000..1519273f --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/LoginAttemptServiceImpl.java @@ -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> 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); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java b/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java index fbfdbc0b..63c0f88e 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java @@ -66,8 +66,8 @@ public class UserServiceImpl implements UserService { } @Override - public JWTToken login(LoginReq loginReq) { - return userDao.login(loginReq); + public JWTToken login(LoginReq loginReq,HttpServletRequest request) { + return userDao.login(loginReq,request); } @@ -119,4 +119,9 @@ public class UserServiceImpl implements UserService { public UserEntity getUserByBeneficiaryId(Long beneficiaryId) { return userDao.getUserByBeneficiaryId(beneficiaryId); } + @Override + public UserEntity getUserEntityById(Long userId) { + // Calling DAO Function + return userDao.validateUser(userId); + } } \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/util/Utils.java b/src/main/java/net/gepafin/tendermanagement/util/Utils.java index d7da174b..767872ce 100644 --- a/src/main/java/net/gepafin/tendermanagement/util/Utils.java +++ b/src/main/java/net/gepafin/tendermanagement/util/Utils.java @@ -4,15 +4,13 @@ import java.lang.reflect.Field; import java.lang.reflect.Type; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.regex.Pattern; import java.util.stream.Collectors; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.collections4.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -302,5 +300,12 @@ public class Utils { private static String replaceNull(String text, String target, String 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(); + } } diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/LoginAttemptApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/LoginAttemptApi.java new file mode 100644 index 00000000..379a1d05 --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/LoginAttemptApi.java @@ -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 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>> 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> createLoginAttempt(@ApiParam(value = "login attempt request", required = true) @Valid @RequestBody LoginAttemptReq loginAttemptReq, HttpServletRequest request) { + return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/PdfApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/PdfApi.java deleted file mode 100644 index a8f7ea48..00000000 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/PdfApi.java +++ /dev/null @@ -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 generateApplicationPdf( - HttpServletRequest request, - @Parameter(description = "The application id", required = true) - @PathVariable(value = "applicationId", required = true) Long applicationId); -} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java index 6bb6a388..32f34963 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/UserApi.java @@ -104,7 +104,7 @@ public interface UserApi { @RequestMapping(value = "/login", produces = {"application/json"}, method = RequestMethod.POST) - ResponseEntity> login( + ResponseEntity> login(HttpServletRequest request, @Parameter(description = "Login request object", required = true) @Valid @RequestBody LoginReq loginReq); @Operation(summary = "Api to initiate password reset request", responses = { diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/LoginAttemptApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/LoginAttemptApiController.java new file mode 100644 index 00000000..ed3a048b --- /dev/null +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/LoginAttemptApiController.java @@ -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>> getLoginAttemptsList(Integer pageNo, Integer pageLimit) { + LoginAttemptPageableResponseBean> response = loginAttemptService.getLoginAttemptsList(pageNo, pageLimit); + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + @Override + public ResponseEntity> createLoginAttempt(LoginAttemptReq loginAttemptReq, HttpServletRequest request) { + Map 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(null, Status.SUCCESS, Translator.toLocale(GepafinConstant.LOGIN_ATTEMPTED_CREATED_SUCCESSFULLY))); + } +} diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PdfController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PdfController.java deleted file mode 100644 index f14451ed..00000000 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/PdfController.java +++ /dev/null @@ -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 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); - } -} - diff --git a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java index 4ffd3e87..c6c57b0d 100644 --- a/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java +++ b/src/main/java/net/gepafin/tendermanagement/web/rest/api/impl/UserApiController.java @@ -70,10 +70,10 @@ public class UserApiController implements UserApi { } @Override - public ResponseEntity> login( + public ResponseEntity> login(HttpServletRequest request, @Valid @RequestBody LoginReq loginReq) { 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))); } @Override diff --git a/src/main/resources/db/changelog/db.changelog-1.0.0.xml b/src/main/resources/db/changelog/db.changelog-1.0.0.xml index 03f3d5db..eceb9426 100644 --- a/src/main/resources/db/changelog/db.changelog-1.0.0.xml +++ b/src/main/resources/db/changelog/db.changelog-1.0.0.xml @@ -1052,4 +1052,35 @@ path="db/dump/update_system_email_template_of_application_submission.sql" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index 31a22928..2e384261 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -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. 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. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 74b6e2b7..022c23db 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -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. 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.