diff --git a/src/main/java/net/gepafin/tendermanagement/config/jwt/TokenProvider.java b/src/main/java/net/gepafin/tendermanagement/config/jwt/TokenProvider.java index 3068fefb..15c51b7a 100644 --- a/src/main/java/net/gepafin/tendermanagement/config/jwt/TokenProvider.java +++ b/src/main/java/net/gepafin/tendermanagement/config/jwt/TokenProvider.java @@ -6,12 +6,18 @@ import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; import jakarta.annotation.PostConstruct; import jakarta.servlet.http.HttpServletRequest; +import net.gepafin.tendermanagement.config.Translator; +import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.UserEntity; +import net.gepafin.tendermanagement.repositories.UserRepository; import net.gepafin.tendermanagement.util.Utils; +import net.gepafin.tendermanagement.web.rest.api.errors.Status; +import net.gepafin.tendermanagement.web.rest.api.errors.UnauthorizedAccessException; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.time.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -40,23 +46,43 @@ public class TokenProvider { @Value("${security.authentication.jwt.token-validity-in-seconds}") private long tokenValidityInSeconds; + @Autowired + private UserRepository userRepository; private SecretKey key; private static final String AUTHORITIES_KEY = "auth"; private static final String MERCHANTID="merchantId"; - public static final String INVALID_USER = "invalid_user"; static final String AUTH_SECRET = "X-Api-Secret"; private final Set invalidatedTokens = new HashSet<>(); + private static final String USER_ID = "userId"; + public UserEntity validateUser(Map userInfo) { + if (userInfo == null || userInfo.get(USER_ID) == null) { + throw new UnauthorizedAccessException(Status.UNAUTHORIZED, Translator.toLocale(GepafinConstant.INVALID_USER)); + } + + Long userId = Long.valueOf(userInfo.get(USER_ID).toString()); + UserEntity userEntity = userRepository.findById(userId).orElse(null); + + if (userEntity == null) { + throw new UnauthorizedAccessException(Status.UNAUTHORIZED, Translator.toLocale(GepafinConstant.INVALID_USER)); + } + + if (!userEntity.getStatus().equals("ACTIVE")) { + throw new UnauthorizedAccessException(Status.UNAUTHORIZED, Translator.toLocale(GepafinConstant.INVALID_USER)); + } + + return userEntity; + } @PostConstruct public void init() { this.key = Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)); log.info("JWT Secret Key initialized."); } - public String createToken(Authentication authentication, Boolean rememberMe, UserEntity user) { + public String createToken(Authentication authentication, Boolean rememberMe, UserEntity user) { String authorities = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); @@ -72,11 +98,11 @@ public class TokenProvider { validity = new Date(now + (this.tokenValidityInSeconds * 1000)); log.info("Creating token with standard validity of {} seconds.", this.tokenValidityInSeconds); } - + String payload = authentication.getName(); if(user != null) { - payload += ":"+user.getId(); - } + payload += ":"+user.getId(); + } String token = Jwts.builder() .setSubject(payload) @@ -160,7 +186,7 @@ public class TokenProvider { // isSuperAdmin = true; // // } else - if (!isEmpty(authSecretHeader)) { + if (!isEmpty(authSecretHeader)) { String secret = Utils.decodeBase64String(authSecretHeader); String[] tokenArr = secret.split("\\.", 2); String[] merchant = tokenArr[0].split("-"); @@ -175,12 +201,12 @@ public class TokenProvider { if (payload != null && !isSuperAdmin) { String[] payloadString = payload.split(":");{ - if (payloadString.length > 1) { + if (payloadString.length > 1) { // userInfo.put(MERCHANTID, payloadString[1]); // userInfo.put("associatedTags", payloadString[2]); - userInfo.put("userId", payloadString[1]); + userInfo.put("userId", payloadString[1]); + } } - } if (payloadString.length > 1) { // userInfo.put(MERCHANTID, payloadString[1]); @@ -203,7 +229,7 @@ public class TokenProvider { Gson g = new Gson(); return g.fromJson(new String(decoder.decode(parts[1])), Map.class); } -// public String getSuperUserToken() { + // public String getSuperUserToken() { // return superUserToken; // } public String getUserDetails(String token) { @@ -218,4 +244,4 @@ public class TokenProvider { return null; // Return null if token is not found or not in Bearer format } -} +} \ No newline at end of file diff --git a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java index 74fad92c..70257104 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -102,5 +102,6 @@ public class GepafinConstant { public static final String INVALID_STATUS_CHANGE_FROM_DRAFT = "invalid.status.change.from.draft"; public static final String STATUS_CANNOT_BE_CHANGED = "status.cannot.be.changed"; public static final String PUBLISHED_CALL_NOT_UPDATE = "published.call.not.update"; + public static final String INVALID_USER = "invalid_user"; } diff --git a/src/main/java/net/gepafin/tendermanagement/dao/RoleDao.java b/src/main/java/net/gepafin/tendermanagement/dao/RoleDao.java index 2f5627cc..200b9916 100644 --- a/src/main/java/net/gepafin/tendermanagement/dao/RoleDao.java +++ b/src/main/java/net/gepafin/tendermanagement/dao/RoleDao.java @@ -16,6 +16,8 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -30,7 +32,7 @@ public class RoleDao { @Autowired private RegionDao regionDao; - + private RoleEntity roleEntity; public RoleResponseBean createRole(RoleReq roleReq) { log.info("Creating new role with details: {}", roleReq); RoleEntity roleEntity = convertRoleRequestToRoleEntity(roleReq); @@ -43,7 +45,7 @@ public class RoleDao { RoleEntity roleEntity = new RoleEntity(); roleEntity.setRoleName(roleReq.getRoleName()); roleEntity.setRoleType(roleReq.getRoleType()); - roleEntity.setPermissions(roleReq.getPermissions()); + roleEntity.setPermissions(String.join(",", roleReq.getPermissions())); roleEntity.setDescription(roleReq.getDescription()); RegionEntity regionEntity =regionDao.validateRegion(roleReq.getRegionId()); roleEntity.setRegion(regionEntity); @@ -51,6 +53,7 @@ public class RoleDao { } public RoleResponseBean convertRoleEntityToRoleResponse(RoleEntity roleEntity) { + this.roleEntity = roleEntity; RoleResponseBean roleResponseBean = new RoleResponseBean(); roleResponseBean.setId(roleEntity.getId()); roleResponseBean.setCreatedDate(roleEntity.getCreatedDate()); @@ -58,7 +61,11 @@ public class RoleDao { roleResponseBean.setRoleName(roleEntity.getRoleName()); roleResponseBean.setRoleType(roleEntity.getRoleType()); roleResponseBean.setDescription(roleEntity.getDescription()); - roleResponseBean.setPermissions(roleEntity.getPermissions()); + String permissionsString = roleEntity.getPermissions(); + List permissionsList = permissionsString != null && !permissionsString.isEmpty() + ? Arrays.asList(permissionsString.split(",")) + : new ArrayList<>(); + roleResponseBean.setPermissions(permissionsList); RegionResponseBean regionResponseBean = regionDao.convertRegionEntityToRegionResponse(roleEntity.getRegion()); roleResponseBean.setRegion(regionResponseBean); return roleResponseBean; @@ -75,7 +82,7 @@ public class RoleDao { setIfUpdated(existingRole::getRoleName, existingRole::setRoleName, roleReq.getRoleName()); setIfUpdated(existingRole::getRoleType, existingRole::setRoleType, roleReq.getRoleType()); setIfUpdated(existingRole::getDescription, existingRole::setDescription, roleReq.getDescription()); - setIfUpdated(existingRole::getPermissions, existingRole::setPermissions, roleReq.getPermissions()); + setIfUpdated(existingRole::getPermissions, existingRole::setPermissions, String.join(",", roleReq.getPermissions())); existingRole = roleRepository.save(existingRole); @@ -109,7 +116,7 @@ public class RoleDao { log.info("Fetching all roles"); List roles = roleRepository.findAll() .stream() - .map(roleEntity -> Utils.convertObject(roleEntity, RoleResponseBean.class)) + .map(this::convertRoleEntityToRoleResponse) .collect(Collectors.toList()); log.info("Total roles found: {}", roles.size()); return roles; diff --git a/src/main/java/net/gepafin/tendermanagement/model/request/RoleReq.java b/src/main/java/net/gepafin/tendermanagement/model/request/RoleReq.java index 50cf17ce..cd5e81d1 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/request/RoleReq.java +++ b/src/main/java/net/gepafin/tendermanagement/model/request/RoleReq.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import lombok.Setter; +import java.util.List; + @Getter @Setter public class RoleReq { @@ -16,7 +18,7 @@ public class RoleReq { private String description; - private String permissions; + private List permissions; private Long regionId; diff --git a/src/main/java/net/gepafin/tendermanagement/model/response/RoleResponseBean.java b/src/main/java/net/gepafin/tendermanagement/model/response/RoleResponseBean.java index da097f48..93917e99 100644 --- a/src/main/java/net/gepafin/tendermanagement/model/response/RoleResponseBean.java +++ b/src/main/java/net/gepafin/tendermanagement/model/response/RoleResponseBean.java @@ -7,12 +7,13 @@ import net.gepafin.tendermanagement.entities.RegionEntity; import net.gepafin.tendermanagement.model.BaseBean; import java.time.LocalDateTime; +import java.util.List; @Data public class RoleResponseBean extends BaseBean { private String roleName; private String description; - private String permissions; + private List permissions; private RegionResponseBean region; private String roleType; } diff --git a/src/main/java/net/gepafin/tendermanagement/service/UserService.java b/src/main/java/net/gepafin/tendermanagement/service/UserService.java index 7764c98f..f925d7dd 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/UserService.java +++ b/src/main/java/net/gepafin/tendermanagement/service/UserService.java @@ -33,4 +33,6 @@ public interface UserService { void logoutUser(HttpServletRequest request, HttpServletResponse response); UserResponseBean updateUserStatus(Long userId, UserStatusEnum statusReq); + + UserResponseBean getValidUser(HttpServletRequest request); } 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 bb2446b7..9dc8378e 100644 --- a/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java +++ b/src/main/java/net/gepafin/tendermanagement/service/impl/UserServiceImpl.java @@ -2,6 +2,7 @@ package net.gepafin.tendermanagement.service.impl; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import net.gepafin.tendermanagement.config.jwt.TokenProvider; import net.gepafin.tendermanagement.dao.UserDao; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.model.request.LoginReq; @@ -16,12 +17,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Map; + @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; + @Autowired + private TokenProvider tokenProvider; @Transactional(rollbackFor = Exception.class) public UserResponseBean createUser(UserReq userReq) { @@ -52,7 +57,7 @@ public class UserServiceImpl implements UserService { return userDao.login(loginReq); } - + @Override public UserEntity validateUser(Long userId) { return userDao.validateUser(userId); @@ -81,4 +86,11 @@ public class UserServiceImpl implements UserService { return userDao.updateUserStatus(userId, statusReq); } + @Override + @Transactional(readOnly = true) + public UserResponseBean getValidUser(HttpServletRequest request) { + Map userInfo= tokenProvider.getUserInfoAndUserIdFromToken(request); + UserEntity user=tokenProvider.validateUser(userInfo); + return userDao.getUserById(user.getId()); + } } \ No newline at end of file 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 c60cef58..fcf6b41e 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 @@ -11,6 +11,7 @@ import jakarta.validation.Valid; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.model.request.*; +import net.gepafin.tendermanagement.model.response.RoleResponseBean; import net.gepafin.tendermanagement.model.response.UserResponseBean; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.Response; @@ -22,6 +23,8 @@ import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + @Validated public interface UserApi { @@ -174,7 +177,18 @@ public interface UserApi { @Parameter(description = "status", required = true)@RequestParam(value = "status", required = true) UserStatusEnum status) { return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED); } - + @Operation(summary = "Api to get valid user from token", + responses = { + @ApiResponse(responseCode = "200", description = "OK"), + @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) })) }) + @GetMapping(value = "/me", + produces = { "application/json" }) + ResponseEntity> getValidUser(HttpServletRequest request); } 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 fb4801b7..b42c869d 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 @@ -9,6 +9,7 @@ import net.gepafin.tendermanagement.constants.GepafinConstant; import net.gepafin.tendermanagement.entities.UserEntity; import net.gepafin.tendermanagement.enums.UserStatusEnum; import net.gepafin.tendermanagement.model.request.*; +import net.gepafin.tendermanagement.model.response.RoleResponseBean; import net.gepafin.tendermanagement.model.response.UserResponseBean; import net.gepafin.tendermanagement.model.util.JWTToken; import net.gepafin.tendermanagement.model.util.Response; @@ -23,6 +24,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import java.util.List; + @RestController @RequestMapping("${openapi.gepafin.base-path:/v1/user}") @Validated @@ -118,5 +121,12 @@ public class UserApiController implements UserApi { UserResponseBean updatedUser = userService.updateUserStatus(userId, status); return ResponseEntity.ok(new Response<>(updatedUser, Status.SUCCESS, Translator.toLocale(GepafinConstant.UPDATE_USER_STATUS_SUCCESS_MSG))); } + @Override + public ResponseEntity> getValidUser(HttpServletRequest request) { + log.info("Get Valid User Detail"); + UserResponseBean user = userService.getValidUser(request); + return ResponseEntity.status(HttpStatus.OK) + .body(new Response<>(user, Status.SUCCESS, Translator.toLocale(GepafinConstant.GET_USER_SUCCESS_MSG))); + } } \ No newline at end of file diff --git a/src/main/resources/message_en.properties b/src/main/resources/message_en.properties index c581f97c..444f8a64 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -63,6 +63,7 @@ published.call.not.update=Published call cannot be updated. login.successfully=Login successfully. pass.min.len.msg=Password must be at least 8 characters long. email.already.exists=A user with this email already exists. +invalid_user=User validation failed. Check user info, account status, and token expiration. #Global messages common_message=Something went wrong..Please try again.. diff --git a/src/main/resources/message_it.properties b/src/main/resources/message_it.properties index 15264c64..8d7352f9 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -62,6 +62,7 @@ published.call.not.update=Il bando pubblicato non pu� essere aggiornato. login.successfully=Accesso effettuato con successo. pass.min.len.msg=La password deve essere lunga almeno 8 caratteri. email.already.exists=Esiste gi� un utente con questa email. +invalid_user=Validazione utente fallita. Controlla le informazioni, lo stato dell'account e la scadenza del token. #Global messages common_message=qualcosa é andato storto. Per favore riprova