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 ed1b30d4..8d03b817 100644 --- a/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java +++ b/src/main/java/net/gepafin/tendermanagement/constants/GepafinConstant.java @@ -83,5 +83,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/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 10f36d79..590f845e 100644 --- a/src/main/resources/message_en.properties +++ b/src/main/resources/message_en.properties @@ -62,6 +62,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 2d1fcc5f..dbceec17 100644 --- a/src/main/resources/message_it.properties +++ b/src/main/resources/message_it.properties @@ -61,6 +61,7 @@ published.call.not.update=Il bando pubblicato non pu 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