From fbe6878daa7263d19ff664db3c9a3243567ede93 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Mon, 2 Dec 2024 11:40:55 +0530 Subject: [PATCH 1/6] jwt api implementation --- pom.xml | 20 ++++ src/main/environment/ecd_ci.properties | 1 + src/main/environment/ecd_dev.properties | 1 + src/main/environment/ecd_test.properties | 1 + src/main/environment/ecd_uat.properties | 1 + src/main/java/com/iemr/ecd/dao/Users.java | 100 ++++++++++++++++ .../ecd/repository/ecd/UserLoginRepo.java | 17 +++ .../com/iemr/ecd/utils/mapper/CookieUtil.java | 45 +++++++ .../iemr/ecd/utils/mapper/FilterConfig.java | 19 +++ .../utils/mapper/JwtAuthenticationUtil.java | 92 ++++++++++++++ .../mapper/JwtUserIdValidationFilter.java | 112 ++++++++++++++++++ .../com/iemr/ecd/utils/mapper/JwtUtil.java | 77 ++++++++++++ 12 files changed, 486 insertions(+) create mode 100644 src/main/java/com/iemr/ecd/dao/Users.java create mode 100644 src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java create mode 100644 src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java create mode 100644 src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java create mode 100644 src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java create mode 100644 src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java create mode 100644 src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java diff --git a/pom.xml b/pom.xml index 232965b..f52192e 100644 --- a/pom.xml +++ b/pom.xml @@ -232,6 +232,26 @@ jackson-core 2.17.0-rc1 + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime + diff --git a/src/main/environment/ecd_ci.properties b/src/main/environment/ecd_ci.properties index 751772e..65669a8 100644 --- a/src/main/environment/ecd_ci.properties +++ b/src/main/environment/ecd_ci.properties @@ -15,3 +15,4 @@ registerBeneficiaryUrl=@env.COMMON_API_BASE_URL@/beneficiary/create ##Beneficiary Edit Url beneficiaryEditUrl =@env.COMMON_API_BASE_URL@/beneficiary/update +jwt.secret= diff --git a/src/main/environment/ecd_dev.properties b/src/main/environment/ecd_dev.properties index 55dd698..c65a0e6 100644 --- a/src/main/environment/ecd_dev.properties +++ b/src/main/environment/ecd_dev.properties @@ -15,3 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update +jwt.secret= diff --git a/src/main/environment/ecd_test.properties b/src/main/environment/ecd_test.properties index 55dd698..c65a0e6 100644 --- a/src/main/environment/ecd_test.properties +++ b/src/main/environment/ecd_test.properties @@ -15,3 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update +jwt.secret= diff --git a/src/main/environment/ecd_uat.properties b/src/main/environment/ecd_uat.properties index 55dd698..c65a0e6 100644 --- a/src/main/environment/ecd_uat.properties +++ b/src/main/environment/ecd_uat.properties @@ -15,3 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update +jwt.secret= diff --git a/src/main/java/com/iemr/ecd/dao/Users.java b/src/main/java/com/iemr/ecd/dao/Users.java new file mode 100644 index 0000000..5ad1027 --- /dev/null +++ b/src/main/java/com/iemr/ecd/dao/Users.java @@ -0,0 +1,100 @@ +package com.iemr.ecd.dao; + +import java.sql.Timestamp; + +import com.google.gson.annotations.Expose; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; + +@Data +@Entity +@Table(name = "m_user") +public class Users { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Expose + @Column(name = "UserID") + private Long userID; + @Expose + @Column(name = "TitleID") private Short titleID; + @Expose + @Column(name = "FirstName") + private String firstName; + @Expose + @Column(name = "MiddleName") + private String middleName; + @Expose + @Column(name = "lastName") + private String lastName; + @Expose + @Column(name = "GenderID") + private Short genderID; + @Expose + @Column(name = "MaritalStatusID") + private Short maritalStatusID; + @Expose + @Column(name = "AadhaarNo") + private String aadhaarNo; + @Expose + @Column(name = "PAN") + private String pan; + @Expose + @Column(name = "DOB") + private Timestamp dob; + @Expose + @Column(name = "DOJ") + private Timestamp doj; + @Expose + @Column(name = "QualificationID") + private Integer qualificationID; + @Expose + @Column(name = "UserName") + private String userName; + @Expose + @Column(name = "Password") + private String password; + @Expose + @Column(name = "AgentID") + private String agentID; + @Expose + @Column(name = "AgentPassword") + private String agentPassword; + @Expose + @Column(name = "EmailID") + private String emailID; + @Expose + @Column(name = "StatusID") + private Short statusID; + @Expose + @Column(name = "EmergencyContactPerson") + private String emergencyContactPerson; + @Expose + @Column(name = "EmergencyContactNo") + private String emergencyContactNo; + @Expose + @Column(name = "IsSupervisor") + private Boolean isSupervisor; + @Expose + @Column(name = "Deleted") + private Boolean deleted; + @Expose + @Column(name = "CreatedBy") + private String createdBy; + @Expose + @Column(name = "CreatedDate") + private Timestamp createdDate; + @Expose + @Column(name = "ModifiedBy") + private String modifiedBy; + @Expose + @Column(name = "LastModDate") + private Timestamp lastModDate; + +} + diff --git a/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java b/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java new file mode 100644 index 0000000..36967f5 --- /dev/null +++ b/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java @@ -0,0 +1,17 @@ +package com.iemr.ecd.repository.ecd; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.iemr.ecd.dao.Users; + + +@Repository +public interface UserLoginRepo extends CrudRepository { + + @Query(" SELECT u FROM Users u WHERE u.userID = :userID AND u.deleted = false ") + public Users getUserByUserID(@Param("userID") Long userID); + +} diff --git a/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java new file mode 100644 index 0000000..44e593a --- /dev/null +++ b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java @@ -0,0 +1,45 @@ +package com.iemr.ecd.utils.mapper; + +import java.util.Arrays; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Service +public class CookieUtil { + + public Optional getCookieValue(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookieName.equals(cookie.getName())) { + return Optional.of(cookie.getValue()); + } + } + } + return Optional.empty(); + } + + public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response) { + // Create a new cookie with the JWT token + Cookie cookie = new Cookie("Jwttoken", Jwttoken); + cookie.setHttpOnly(true); // Prevent JavaScript access for security + cookie.setSecure(true); // Ensure the cookie is sent only over HTTPS + cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time + cookie.setPath("/"); // Make the cookie available for the entire application + response.addCookie(cookie); // Add the cookie to the response + } + + public String getJwtTokenFromCookie(HttpServletRequest request) { + return Arrays.stream(request.getCookies()) + .filter(cookie -> "Jwttoken".equals(cookie.getName())) + .map(Cookie::getValue) + .findFirst() + .orElse(null); + } +} + diff --git a/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java b/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java new file mode 100644 index 0000000..5810023 --- /dev/null +++ b/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java @@ -0,0 +1,19 @@ +package com.iemr.ecd.utils.mapper; + +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration +public class FilterConfig { + + @Bean + public FilterRegistrationBean jwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil)); + registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints + return registrationBean; + } + +} diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java new file mode 100644 index 0000000..1b0e4e2 --- /dev/null +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java @@ -0,0 +1,92 @@ +package com.iemr.ecd.utils.mapper; + +import java.util.Optional; + +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.stereotype.Component; + +import com.iemr.ecd.dao.Users; +import com.iemr.ecd.repository.ecd.UserLoginRepo; +import com.iemr.ecd.utils.advice.exception_handler.ECDException; + +import io.jsonwebtoken.Claims; +import jakarta.servlet.http.HttpServletRequest; + +@Component +public class JwtAuthenticationUtil { + + @Autowired + private final CookieUtil cookieUtil; + @Autowired + private final JwtUtil jwtUtil; + @Autowired + private UserLoginRepo userLoginRepo; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + + public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { + this.cookieUtil = cookieUtil; + this.jwtUtil = jwtUtil; + } + + public ResponseEntity validateJwtToken(HttpServletRequest request) { + Optional jwtTokenOpt = cookieUtil.getCookieValue(request, "Jwttoken"); + + if (jwtTokenOpt.isEmpty()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("Error 401: Unauthorized - JWT Token is not set!"); + } + + String jwtToken = jwtTokenOpt.get(); + + // Validate the token + Claims claims = jwtUtil.validateToken(jwtToken); + if (claims == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Error 401: Unauthorized - Invalid JWT Token!"); + } + + // Extract username from token + String usernameFromToken = claims.getSubject(); + if (usernameFromToken == null || usernameFromToken.isEmpty()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Error 401: Unauthorized - Username is missing!"); + } + + // Return the username if valid + return ResponseEntity.ok(usernameFromToken); + } + + public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { + try { + // Validate JWT token and extract claims + Claims claims = jwtUtil.validateToken(jwtToken); + + if (claims == null) { + throw new ECDException("Invalid JWT token."); + } + + String userId = claims.get("userId", String.class); + String tokenUsername = jwtUtil.extractUsername(jwtToken); + + // Fetch user based on userId from the database or cache + Users user = userLoginRepo.getUserByUserID(Long.parseLong(userId)); + if (user == null) { + throw new ECDException("Invalid User ID."); + } + + // Check if the token's username matches the user retrieved by userId + if (!user.getUserName().equalsIgnoreCase(tokenUsername)) { + throw new ECDException("JWT token and User ID mismatch."); + } + + return true; // Valid userId and JWT token + } catch (Exception e) { + logger.error("Validation failed: " + e.getMessage(), e); + throw new Exception("Validation error: " + e.getMessage(), e); + } + } +} + diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java new file mode 100644 index 0000000..98683d9 --- /dev/null +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java @@ -0,0 +1,112 @@ +package com.iemr.ecd.utils.mapper; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JwtUserIdValidationFilter implements Filter { + + private final JwtAuthenticationUtil jwtAuthenticationUtil; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { + this.jwtAuthenticationUtil = jwtAuthenticationUtil; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + String path = request.getRequestURI(); + String contextPath = request.getContextPath(); + logger.info("JwtUserIdValidationFilter invoked for path: " + path); + + // Log cookies for debugging + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if ("userId".equals(cookie.getName())) { + logger.warn("userId found in cookies! Clearing it..."); + clearUserIdCookie(response); // Explicitly remove userId cookie + } + } + } else { + logger.info("No cookies found in the request"); + } + + + // Log headers for debugging + String jwtTokenFromHeader = request.getHeader("Jwttoken"); + logger.info("JWT token from header: " + jwtTokenFromHeader); + + // Skip login and public endpoints + if (path.equals(contextPath + "/user/userAuthenticate") || + path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession") || + path.startsWith(contextPath + "/public")) { + logger.info("Skipping filter for path: " + path); + filterChain.doFilter(servletRequest, servletResponse); + return; + } + + try { + // Retrieve JWT token from cookies + String jwtTokenFromCookie = getJwtTokenFromCookies(request); + logger.info("JWT token from cookie: " + jwtTokenFromCookie); + + // Determine which token (cookie or header) to validate + String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader; + if (jwtToken == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token not found in cookies or headers"); + return; + } + + // Validate JWT token and userId + boolean isValid = jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken); + + if (isValid) { + // If token is valid, allow the request to proceed + filterChain.doFilter(servletRequest, servletResponse); + } else { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token"); + } + } catch (Exception e) { + logger.error("Authorization error: ", e); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); + } + } + + private String getJwtTokenFromCookies(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("Jwttoken")) { + return cookie.getValue(); + } + } + } + return null; + } + + private void clearUserIdCookie(HttpServletResponse response) { + Cookie cookie = new Cookie("userId", null); + cookie.setPath("/"); + cookie.setMaxAge(0); // Invalidate the cookie + response.addCookie(cookie); + } +} + diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java new file mode 100644 index 0000000..b0cf5fd --- /dev/null +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java @@ -0,0 +1,77 @@ +package com.iemr.ecd.utils.mapper; + +import java.security.Key; +import java.util.Date; +import java.util.function.Function; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; + +@Component +public class JwtUtil { + + @Value("${jwt.secret}") + private String SECRET_KEY; + + private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 1 day in milliseconds + + // Generate a key using the secret + private Key getSigningKey() { + if (SECRET_KEY == null || SECRET_KEY.isEmpty()) { + throw new IllegalStateException("JWT secret key is not set in application.properties"); + } + return Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); + } + + // Generate JWT Token + public String generateToken(String username, String userId) { + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME); + + // Include the userId in the JWT claims + return Jwts.builder() + .setSubject(username) + .claim("userId", userId) // Add userId as a claim + .setIssuedAt(now) + .setExpiration(expiryDate) + .signWith(getSigningKey(), SignatureAlgorithm.HS256) + .compact(); + } + + + // Validate and parse JWT Token + public Claims validateToken(String token) { + try { + return Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } catch (Exception e) { + return null; // Handle token parsing/validation errors + } + } + + public String extractUsername(String token) { + return extractClaim(token, Claims::getSubject); + } + + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + private Claims extractAllClaims(String token) { + return Jwts.parserBuilder() + .setSigningKey(getSigningKey()) + .build() + .parseClaimsJws(token) + .getBody(); + } +} + From 54236e3b68da064aad004a2389e3b94ba481a4d0 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Thu, 5 Dec 2024 15:28:16 +0530 Subject: [PATCH 2/6] Formatting and dependency upgrade --- pom.xml | 48 ++--- .../com/iemr/ecd/utils/mapper/CookieUtil.java | 56 +++--- .../iemr/ecd/utils/mapper/FilterConfig.java | 16 +- .../utils/mapper/JwtAuthenticationUtil.java | 139 +++++++------- .../mapper/JwtUserIdValidationFilter.java | 179 +++++++++--------- .../com/iemr/ecd/utils/mapper/JwtUtil.java | 74 +++----- 6 files changed, 241 insertions(+), 271 deletions(-) diff --git a/pom.xml b/pom.xml index f52192e..35410b3 100644 --- a/pom.xml +++ b/pom.xml @@ -28,25 +28,21 @@ 1.2.0.Final - + org.springframework.boot spring-boot-starter-aop 3.2.2 - - co.elastic.logging - logback-ecs-encoder - 1.3.2 + + co.elastic.logging + logback-ecs-encoder + 1.3.2 - + org.slf4j slf4j-api @@ -101,8 +97,7 @@ 8.2.0 - + jakarta.persistence jakarta.persistence-api @@ -169,15 +164,14 @@ org.apache.poi poi-ooxml 5.2.5 - - - - - - + + + + + + - + org.springframework.boot spring-boot-starter-data-redis @@ -219,8 +213,7 @@ jackson-datatype-joda 2.17.0 - + com.fasterxml.jackson.core jackson-databind @@ -236,20 +229,20 @@ io.jsonwebtoken jjwt-api - 0.11.5 + 0.12.6 io.jsonwebtoken jjwt-impl - 0.11.5 + 0.12.6 runtime io.jsonwebtoken jjwt-jackson - 0.11.5 + 0.12.6 runtime @@ -335,8 +328,7 @@ ${target-properties} and ${source-properties} - diff --git a/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java index 44e593a..397aece 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java @@ -12,34 +12,30 @@ @Service public class CookieUtil { - public Optional getCookieValue(HttpServletRequest request, String cookieName) { - Cookie[] cookies = request.getCookies(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookieName.equals(cookie.getName())) { - return Optional.of(cookie.getValue()); - } - } - } - return Optional.empty(); - } - - public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response) { - // Create a new cookie with the JWT token - Cookie cookie = new Cookie("Jwttoken", Jwttoken); - cookie.setHttpOnly(true); // Prevent JavaScript access for security - cookie.setSecure(true); // Ensure the cookie is sent only over HTTPS - cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time - cookie.setPath("/"); // Make the cookie available for the entire application - response.addCookie(cookie); // Add the cookie to the response - } - - public String getJwtTokenFromCookie(HttpServletRequest request) { - return Arrays.stream(request.getCookies()) - .filter(cookie -> "Jwttoken".equals(cookie.getName())) - .map(Cookie::getValue) - .findFirst() - .orElse(null); - } + public Optional getCookieValue(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookieName.equals(cookie.getName())) { + return Optional.of(cookie.getValue()); + } + } + } + return Optional.empty(); + } + + public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response) { + // Create a new cookie with the JWT token + Cookie cookie = new Cookie("Jwttoken", Jwttoken); + cookie.setHttpOnly(true); // Prevent JavaScript access for security + cookie.setSecure(true); // Ensure the cookie is sent only over HTTPS + cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time + cookie.setPath("/"); // Make the cookie available for the entire application + response.addCookie(cookie); // Add the cookie to the response + } + + public String getJwtTokenFromCookie(HttpServletRequest request) { + return Arrays.stream(request.getCookies()).filter(cookie -> "Jwttoken".equals(cookie.getName())) + .map(Cookie::getValue).findFirst().orElse(null); + } } - diff --git a/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java b/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java index 5810023..98867f8 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/FilterConfig.java @@ -4,16 +4,16 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - @Configuration public class FilterConfig { - + @Bean - public FilterRegistrationBean jwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil)); - registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints - return registrationBean; - } + public FilterRegistrationBean jwtUserIdValidationFilter( + JwtAuthenticationUtil jwtAuthenticationUtil) { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil)); + registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints + return registrationBean; + } } diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java index 1b0e4e2..7d91664 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java @@ -19,74 +19,73 @@ @Component public class JwtAuthenticationUtil { - @Autowired - private final CookieUtil cookieUtil; - @Autowired - private final JwtUtil jwtUtil; - @Autowired - private UserLoginRepo userLoginRepo; - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - - - public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { - this.cookieUtil = cookieUtil; - this.jwtUtil = jwtUtil; - } - - public ResponseEntity validateJwtToken(HttpServletRequest request) { - Optional jwtTokenOpt = cookieUtil.getCookieValue(request, "Jwttoken"); - - if (jwtTokenOpt.isEmpty()) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body("Error 401: Unauthorized - JWT Token is not set!"); - } - - String jwtToken = jwtTokenOpt.get(); - - // Validate the token - Claims claims = jwtUtil.validateToken(jwtToken); - if (claims == null) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Error 401: Unauthorized - Invalid JWT Token!"); - } - - // Extract username from token - String usernameFromToken = claims.getSubject(); - if (usernameFromToken == null || usernameFromToken.isEmpty()) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Error 401: Unauthorized - Username is missing!"); - } - - // Return the username if valid - return ResponseEntity.ok(usernameFromToken); - } - - public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { - try { - // Validate JWT token and extract claims - Claims claims = jwtUtil.validateToken(jwtToken); - - if (claims == null) { - throw new ECDException("Invalid JWT token."); - } - - String userId = claims.get("userId", String.class); - String tokenUsername = jwtUtil.extractUsername(jwtToken); - - // Fetch user based on userId from the database or cache - Users user = userLoginRepo.getUserByUserID(Long.parseLong(userId)); - if (user == null) { - throw new ECDException("Invalid User ID."); - } - - // Check if the token's username matches the user retrieved by userId - if (!user.getUserName().equalsIgnoreCase(tokenUsername)) { - throw new ECDException("JWT token and User ID mismatch."); - } - - return true; // Valid userId and JWT token - } catch (Exception e) { - logger.error("Validation failed: " + e.getMessage(), e); - throw new Exception("Validation error: " + e.getMessage(), e); - } - } + @Autowired + private final CookieUtil cookieUtil; + @Autowired + private final JwtUtil jwtUtil; + @Autowired + private UserLoginRepo userLoginRepo; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { + this.cookieUtil = cookieUtil; + this.jwtUtil = jwtUtil; + } + + public ResponseEntity validateJwtToken(HttpServletRequest request) { + Optional jwtTokenOpt = cookieUtil.getCookieValue(request, "Jwttoken"); + + if (jwtTokenOpt.isEmpty()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("Error 401: Unauthorized - JWT Token is not set!"); + } + + String jwtToken = jwtTokenOpt.get(); + + // Validate the token + Claims claims = jwtUtil.validateToken(jwtToken); + if (claims == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Error 401: Unauthorized - Invalid JWT Token!"); + } + + // Extract username from token + String usernameFromToken = claims.getSubject(); + if (usernameFromToken == null || usernameFromToken.isEmpty()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("Error 401: Unauthorized - Username is missing!"); + } + + // Return the username if valid + return ResponseEntity.ok(usernameFromToken); + } + + public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { + try { + // Validate JWT token and extract claims + Claims claims = jwtUtil.validateToken(jwtToken); + + if (claims == null) { + throw new ECDException("Invalid JWT token."); + } + + String userId = claims.get("userId", String.class); + String tokenUsername = jwtUtil.extractUsername(jwtToken); + + // Fetch user based on userId from the database or cache + Users user = userLoginRepo.getUserByUserID(Long.parseLong(userId)); + if (user == null) { + throw new ECDException("Invalid User ID."); + } + + // Check if the token's username matches the user retrieved by userId + if (!user.getUserName().equalsIgnoreCase(tokenUsername)) { + throw new ECDException("JWT token and User ID mismatch."); + } + + return true; // Valid userId and JWT token + } catch (Exception e) { + logger.error("Validation failed: " + e.getMessage(), e); + throw new Exception("Validation error: " + e.getMessage(), e); + } + } } - diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java index 98683d9..9f92110 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java @@ -6,7 +6,6 @@ import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; - import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -19,94 +18,92 @@ @Component public class JwtUserIdValidationFilter implements Filter { - private final JwtAuthenticationUtil jwtAuthenticationUtil; - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - - public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { - this.jwtAuthenticationUtil = jwtAuthenticationUtil; - } - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) - throws IOException, ServletException { - HttpServletRequest request = (HttpServletRequest) servletRequest; - HttpServletResponse response = (HttpServletResponse) servletResponse; - - String path = request.getRequestURI(); - String contextPath = request.getContextPath(); - logger.info("JwtUserIdValidationFilter invoked for path: " + path); - - // Log cookies for debugging - Cookie[] cookies = request.getCookies(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if ("userId".equals(cookie.getName())) { - logger.warn("userId found in cookies! Clearing it..."); - clearUserIdCookie(response); // Explicitly remove userId cookie - } - } - } else { - logger.info("No cookies found in the request"); - } - - - // Log headers for debugging - String jwtTokenFromHeader = request.getHeader("Jwttoken"); - logger.info("JWT token from header: " + jwtTokenFromHeader); - - // Skip login and public endpoints - if (path.equals(contextPath + "/user/userAuthenticate") || - path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession") || - path.startsWith(contextPath + "/public")) { - logger.info("Skipping filter for path: " + path); - filterChain.doFilter(servletRequest, servletResponse); - return; - } - - try { - // Retrieve JWT token from cookies - String jwtTokenFromCookie = getJwtTokenFromCookies(request); - logger.info("JWT token from cookie: " + jwtTokenFromCookie); - - // Determine which token (cookie or header) to validate - String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader; - if (jwtToken == null) { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token not found in cookies or headers"); - return; - } - - // Validate JWT token and userId - boolean isValid = jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken); - - if (isValid) { - // If token is valid, allow the request to proceed - filterChain.doFilter(servletRequest, servletResponse); - } else { - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token"); - } - } catch (Exception e) { - logger.error("Authorization error: ", e); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); - } - } - - private String getJwtTokenFromCookies(HttpServletRequest request) { - Cookie[] cookies = request.getCookies(); - if (cookies != null) { - for (Cookie cookie : cookies) { - if (cookie.getName().equals("Jwttoken")) { - return cookie.getValue(); - } - } - } - return null; - } - - private void clearUserIdCookie(HttpServletResponse response) { - Cookie cookie = new Cookie("userId", null); - cookie.setPath("/"); - cookie.setMaxAge(0); // Invalidate the cookie - response.addCookie(cookie); - } + private final JwtAuthenticationUtil jwtAuthenticationUtil; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { + this.jwtAuthenticationUtil = jwtAuthenticationUtil; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + String path = request.getRequestURI(); + String contextPath = request.getContextPath(); + logger.info("JwtUserIdValidationFilter invoked for path: " + path); + + // Log cookies for debugging + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if ("userId".equals(cookie.getName())) { + logger.warn("userId found in cookies! Clearing it..."); + clearUserIdCookie(response); // Explicitly remove userId cookie + } + } + } else { + logger.info("No cookies found in the request"); + } + + // Log headers for debugging + String jwtTokenFromHeader = request.getHeader("Jwttoken"); + logger.info("JWT token from header: " + jwtTokenFromHeader); + + // Skip login and public endpoints + if (path.equals(contextPath + "/user/userAuthenticate") + || path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession") + || path.startsWith(contextPath + "/public")) { + logger.info("Skipping filter for path: " + path); + filterChain.doFilter(servletRequest, servletResponse); + return; + } + + try { + // Retrieve JWT token from cookies + String jwtTokenFromCookie = getJwtTokenFromCookies(request); + logger.info("JWT token from cookie: " + jwtTokenFromCookie); + + // Determine which token (cookie or header) to validate + String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader; + if (jwtToken == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token not found in cookies or headers"); + return; + } + + // Validate JWT token and userId + boolean isValid = jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken); + + if (isValid) { + // If token is valid, allow the request to proceed + filterChain.doFilter(servletRequest, servletResponse); + } else { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token"); + } + } catch (Exception e) { + logger.error("Authorization error: ", e); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); + } + } + + private String getJwtTokenFromCookies(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("Jwttoken")) { + return cookie.getValue(); + } + } + } + return null; + } + + private void clearUserIdCookie(HttpServletResponse response) { + Cookie cookie = new Cookie("userId", null); + cookie.setPath("/"); + cookie.setMaxAge(0); // Invalidate the cookie + response.addCookie(cookie); + } } - diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java index b0cf5fd..4de31de 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java @@ -14,64 +14,50 @@ @Component public class JwtUtil { - + @Value("${jwt.secret}") - private String SECRET_KEY; + private String SECRET_KEY; private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 1 day in milliseconds // Generate a key using the secret - private Key getSigningKey() { - if (SECRET_KEY == null || SECRET_KEY.isEmpty()) { - throw new IllegalStateException("JWT secret key is not set in application.properties"); - } - return Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); - } + private Key getSigningKey() { + if (SECRET_KEY == null || SECRET_KEY.isEmpty()) { + throw new IllegalStateException("JWT secret key is not set in application.properties"); + } + return Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); + } // Generate JWT Token public String generateToken(String username, String userId) { - Date now = new Date(); - Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME); + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME); - // Include the userId in the JWT claims - return Jwts.builder() - .setSubject(username) - .claim("userId", userId) // Add userId as a claim - .setIssuedAt(now) - .setExpiration(expiryDate) - .signWith(getSigningKey(), SignatureAlgorithm.HS256) - .compact(); + // Include the userId in the JWT claims + return Jwts.builder().setSubject(username).claim("userId", userId) // Add userId as a claim + .setIssuedAt(now).setExpiration(expiryDate).signWith(getSigningKey(), SignatureAlgorithm.HS256) + .compact(); } - // Validate and parse JWT Token public Claims validateToken(String token) { - try { - return Jwts.parserBuilder() - .setSigningKey(getSigningKey()) - .build() - .parseClaimsJws(token) - .getBody(); - } catch (Exception e) { - return null; // Handle token parsing/validation errors - } - } + try { + return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody(); + } catch (Exception e) { + return null; // Handle token parsing/validation errors + } + } - public String extractUsername(String token) { - return extractClaim(token, Claims::getSubject); - } + public String extractUsername(String token) { + return extractClaim(token, Claims::getSubject); + } - public T extractClaim(String token, Function claimsResolver) { - final Claims claims = extractAllClaims(token); - return claimsResolver.apply(claims); - } + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } - private Claims extractAllClaims(String token) { - return Jwts.parserBuilder() - .setSigningKey(getSigningKey()) - .build() - .parseClaimsJws(token) - .getBody(); - } + private Claims extractAllClaims(String token) { + return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody(); + } } - From ba5afd4e5251a558f59b66832f1247081b948ece Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Tue, 10 Dec 2024 17:00:42 +0530 Subject: [PATCH 3/6] corrected by code rabbit comments --- src/main/environment/ecd_ci.properties | 2 +- src/main/environment/ecd_dev.properties | 2 +- src/main/environment/ecd_test.properties | 2 +- src/main/environment/ecd_uat.properties | 2 +- .../java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java | 4 ++-- .../com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/environment/ecd_ci.properties b/src/main/environment/ecd_ci.properties index 65669a8..ef9db01 100644 --- a/src/main/environment/ecd_ci.properties +++ b/src/main/environment/ecd_ci.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=@env.COMMON_API_BASE_URL@/beneficiary/create ##Beneficiary Edit Url beneficiaryEditUrl =@env.COMMON_API_BASE_URL@/beneficiary/update -jwt.secret= +jwt.secret=@JWT_SECRET_KEY@ diff --git a/src/main/environment/ecd_dev.properties b/src/main/environment/ecd_dev.properties index c65a0e6..d08cc4a 100644 --- a/src/main/environment/ecd_dev.properties +++ b/src/main/environment/ecd_dev.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update -jwt.secret= +jwt.secret=@JWT_SECRET_KEY@ diff --git a/src/main/environment/ecd_test.properties b/src/main/environment/ecd_test.properties index c65a0e6..d08cc4a 100644 --- a/src/main/environment/ecd_test.properties +++ b/src/main/environment/ecd_test.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update -jwt.secret= +jwt.secret=@JWT_SECRET_KEY@ diff --git a/src/main/environment/ecd_uat.properties b/src/main/environment/ecd_uat.properties index c65a0e6..d08cc4a 100644 --- a/src/main/environment/ecd_uat.properties +++ b/src/main/environment/ecd_uat.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update -jwt.secret= +jwt.secret=@JWT_SECRET_KEY@ diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java index 7d91664..b03f5e1 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java @@ -20,9 +20,9 @@ public class JwtAuthenticationUtil { @Autowired - private final CookieUtil cookieUtil; + private CookieUtil cookieUtil; @Autowired - private final JwtUtil jwtUtil; + private JwtUtil jwtUtil; @Autowired private UserLoginRepo userLoginRepo; private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java index 9f92110..23aac83 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java @@ -50,7 +50,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo // Log headers for debugging String jwtTokenFromHeader = request.getHeader("Jwttoken"); - logger.info("JWT token from header: " + jwtTokenFromHeader); + logger.info("JWT token from header: "); // Skip login and public endpoints if (path.equals(contextPath + "/user/userAuthenticate") @@ -64,7 +64,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo try { // Retrieve JWT token from cookies String jwtTokenFromCookie = getJwtTokenFromCookies(request); - logger.info("JWT token from cookie: " + jwtTokenFromCookie); + logger.info("JWT token from cookie: "); // Determine which token (cookie or header) to validate String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader; From fd0eb9a20260da8378ee7bc1619df1aefa2e6108 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Fri, 13 Dec 2024 20:46:39 +0530 Subject: [PATCH 4/6] fixed issues --- src/main/environment/ecd_ci.properties | 2 +- src/main/environment/ecd_dev.properties | 2 +- src/main/environment/ecd_test.properties | 2 +- src/main/environment/ecd_uat.properties | 2 +- .../java/com/iemr/ecd/utils/mapper/CookieUtil.java | 10 ---------- .../iemr/ecd/utils/mapper/JwtAuthenticationUtil.java | 6 ------ .../ecd/utils/mapper/JwtUserIdValidationFilter.java | 2 ++ src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java | 2 +- 8 files changed, 7 insertions(+), 21 deletions(-) diff --git a/src/main/environment/ecd_ci.properties b/src/main/environment/ecd_ci.properties index ef9db01..5baf03c 100644 --- a/src/main/environment/ecd_ci.properties +++ b/src/main/environment/ecd_ci.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=@env.COMMON_API_BASE_URL@/beneficiary/create ##Beneficiary Edit Url beneficiaryEditUrl =@env.COMMON_API_BASE_URL@/beneficiary/update -jwt.secret=@JWT_SECRET_KEY@ +jwt.secret=@env.JWT_SECRET_KEY@ \ No newline at end of file diff --git a/src/main/environment/ecd_dev.properties b/src/main/environment/ecd_dev.properties index d08cc4a..d6b788c 100644 --- a/src/main/environment/ecd_dev.properties +++ b/src/main/environment/ecd_dev.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update -jwt.secret=@JWT_SECRET_KEY@ +jwt.secret= diff --git a/src/main/environment/ecd_test.properties b/src/main/environment/ecd_test.properties index d08cc4a..d6b788c 100644 --- a/src/main/environment/ecd_test.properties +++ b/src/main/environment/ecd_test.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update -jwt.secret=@JWT_SECRET_KEY@ +jwt.secret= diff --git a/src/main/environment/ecd_uat.properties b/src/main/environment/ecd_uat.properties index d08cc4a..d6b788c 100644 --- a/src/main/environment/ecd_uat.properties +++ b/src/main/environment/ecd_uat.properties @@ -15,4 +15,4 @@ registerBeneficiaryUrl=/commonapi-v1.0/beneficia ##Beneficiary Edit Url beneficiaryEditUrl =/commonapi-v1.0/beneficiary/update -jwt.secret=@JWT_SECRET_KEY@ +jwt.secret= diff --git a/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java index 397aece..d0c24c1 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/CookieUtil.java @@ -24,16 +24,6 @@ public Optional getCookieValue(HttpServletRequest request, String cookie return Optional.empty(); } - public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response) { - // Create a new cookie with the JWT token - Cookie cookie = new Cookie("Jwttoken", Jwttoken); - cookie.setHttpOnly(true); // Prevent JavaScript access for security - cookie.setSecure(true); // Ensure the cookie is sent only over HTTPS - cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time - cookie.setPath("/"); // Make the cookie available for the entire application - response.addCookie(cookie); // Add the cookie to the response - } - public String getJwtTokenFromCookie(HttpServletRequest request) { return Arrays.stream(request.getCookies()).filter(cookie -> "Jwttoken".equals(cookie.getName())) .map(Cookie::getValue).findFirst().orElse(null); diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java index b03f5e1..483e359 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java @@ -69,7 +69,6 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { } String userId = claims.get("userId", String.class); - String tokenUsername = jwtUtil.extractUsername(jwtToken); // Fetch user based on userId from the database or cache Users user = userLoginRepo.getUserByUserID(Long.parseLong(userId)); @@ -77,11 +76,6 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { throw new ECDException("Invalid User ID."); } - // Check if the token's username matches the user retrieved by userId - if (!user.getUserName().equalsIgnoreCase(tokenUsername)) { - throw new ECDException("JWT token and User ID mismatch."); - } - return true; // Valid userId and JWT token } catch (Exception e) { logger.error("Validation failed: " + e.getMessage(), e); diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java index 23aac83..d7d1c09 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUserIdValidationFilter.java @@ -103,6 +103,8 @@ private String getJwtTokenFromCookies(HttpServletRequest request) { private void clearUserIdCookie(HttpServletResponse response) { Cookie cookie = new Cookie("userId", null); cookie.setPath("/"); + cookie.setHttpOnly(true); + cookie.setSecure(true); cookie.setMaxAge(0); // Invalidate the cookie response.addCookie(cookie); } diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java index 4de31de..18630d8 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtUtil.java @@ -18,7 +18,7 @@ public class JwtUtil { @Value("${jwt.secret}") private String SECRET_KEY; - private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 1 day in milliseconds + private static final long EXPIRATION_TIME = 24L * 60 * 60 * 1000; // 1 day in milliseconds // Generate a key using the secret private Key getSigningKey() { From 0ca92ba9f1fc7928f969c8f785353a2c5b17f37c Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Thu, 19 Dec 2024 12:00:38 +0530 Subject: [PATCH 5/6] user fetch from redis concept --- .../java/com/iemr/ecd/EcdApiApplication.java | 22 ++++++++++++++++++ .../java/com/iemr/ecd/config/RedisConfig.java | 23 +++++++++++++++++++ src/main/java/com/iemr/ecd/dao/Users.java | 5 +++- .../ecd/repository/ecd/UserLoginRepo.java | 17 -------------- .../utils/mapper/JwtAuthenticationUtil.java | 23 +++++++++++++++---- 5 files changed, 67 insertions(+), 23 deletions(-) delete mode 100644 src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java diff --git a/src/main/java/com/iemr/ecd/EcdApiApplication.java b/src/main/java/com/iemr/ecd/EcdApiApplication.java index fcba632..5a7f6e7 100644 --- a/src/main/java/com/iemr/ecd/EcdApiApplication.java +++ b/src/main/java/com/iemr/ecd/EcdApiApplication.java @@ -24,6 +24,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import com.iemr.ecd.dao.Users; import io.swagger.v3.oas.annotations.OpenAPIDefinition; import io.swagger.v3.oas.annotations.info.Contact; @@ -37,4 +44,19 @@ public static void main(String[] args) { SpringApplication.run(EcdApiApplication.class, args); } + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + + // Use StringRedisSerializer for keys (userId) + template.setKeySerializer(new StringRedisSerializer()); + + // Use Jackson2JsonRedisSerializer for values (Users objects) + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Users.class); + template.setValueSerializer(serializer); + + return template; + } + } diff --git a/src/main/java/com/iemr/ecd/config/RedisConfig.java b/src/main/java/com/iemr/ecd/config/RedisConfig.java index 22818fa..58cd150 100644 --- a/src/main/java/com/iemr/ecd/config/RedisConfig.java +++ b/src/main/java/com/iemr/ecd/config/RedisConfig.java @@ -22,11 +22,19 @@ package com.iemr.ecd.config; import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import com.iemr.ecd.dao.Users; @Configuration +@EnableCaching public class RedisConfig { private @Value("${spring.redis.host}") String redisHost; @@ -37,4 +45,19 @@ LettuceConnectionFactory lettuceConnectionFactory() { return new LettuceConnectionFactory(redisHost, redisPort); } + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + + // Use StringRedisSerializer for keys (userId) + template.setKeySerializer(new StringRedisSerializer()); + + // Use Jackson2JsonRedisSerializer for values (Users objects) + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Users.class); + template.setValueSerializer(serializer); + + return template; + } + } diff --git a/src/main/java/com/iemr/ecd/dao/Users.java b/src/main/java/com/iemr/ecd/dao/Users.java index 5ad1027..97c9118 100644 --- a/src/main/java/com/iemr/ecd/dao/Users.java +++ b/src/main/java/com/iemr/ecd/dao/Users.java @@ -1,7 +1,9 @@ package com.iemr.ecd.dao; +import java.io.Serializable; import java.sql.Timestamp; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.google.gson.annotations.Expose; import jakarta.persistence.Column; @@ -15,7 +17,8 @@ @Data @Entity @Table(name = "m_user") -public class Users { +@JsonIgnoreProperties(ignoreUnknown = true) +public class Users implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Expose diff --git a/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java b/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java deleted file mode 100644 index 36967f5..0000000 --- a/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.iemr.ecd.repository.ecd; - -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.CrudRepository; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import com.iemr.ecd.dao.Users; - - -@Repository -public interface UserLoginRepo extends CrudRepository { - - @Query(" SELECT u FROM Users u WHERE u.userID = :userID AND u.deleted = false ") - public Users getUserByUserID(@Param("userID") Long userID); - -} diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java index 483e359..792946f 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java @@ -5,12 +5,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import com.iemr.ecd.dao.Users; -import com.iemr.ecd.repository.ecd.UserLoginRepo; import com.iemr.ecd.utils.advice.exception_handler.ECDException; import io.jsonwebtoken.Claims; @@ -24,7 +24,7 @@ public class JwtAuthenticationUtil { @Autowired private JwtUtil jwtUtil; @Autowired - private UserLoginRepo userLoginRepo; + private RedisTemplate redisTemplate; private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { @@ -70,10 +70,10 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { String userId = claims.get("userId", String.class); - // Fetch user based on userId from the database or cache - Users user = userLoginRepo.getUserByUserID(Long.parseLong(userId)); + // Check if user data is present in Redis + Users user = getUserFromCache(userId); if (user == null) { - throw new ECDException("Invalid User ID."); + throw new Exception("Invalid User ID."); } return true; // Valid userId and JWT token @@ -82,4 +82,17 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { throw new Exception("Validation error: " + e.getMessage(), e); } } + + private Users getUserFromCache(String userId) { + String redisKey = "user_" + userId; // The Redis key format + Users user = (Users) redisTemplate.opsForValue().get(redisKey); + + if (user == null) { + logger.warn("User not found in Redis."); + } else { + logger.info("User fetched successfully from Redis."); + } + + return user; // Returns null if not found + } } From 4c392fecddb71e4a8d555989582751af2c4301c6 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Tue, 24 Dec 2024 13:54:30 +0530 Subject: [PATCH 6/6] user fetch concept modify --- .../ecd/repository/ecd/UserLoginRepo.java | 16 ++++++++++ .../utils/mapper/JwtAuthenticationUtil.java | 30 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java diff --git a/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java b/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java new file mode 100644 index 0000000..bae8d1e --- /dev/null +++ b/src/main/java/com/iemr/ecd/repository/ecd/UserLoginRepo.java @@ -0,0 +1,16 @@ +package com.iemr.ecd.repository.ecd; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.iemr.ecd.dao.Users; + +@Repository +public interface UserLoginRepo extends CrudRepository { + + @Query(" SELECT u FROM Users u WHERE u.userID = :userID AND u.deleted = false ") + public Users getUserByUserID(@Param("userID") Long userID); + +} diff --git a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java index 792946f..e72b50a 100644 --- a/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/ecd/utils/mapper/JwtAuthenticationUtil.java @@ -1,6 +1,7 @@ package com.iemr.ecd.utils.mapper; import java.util.Optional; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,6 +12,7 @@ import org.springframework.stereotype.Component; import com.iemr.ecd.dao.Users; +import com.iemr.ecd.repository.ecd.UserLoginRepo; import com.iemr.ecd.utils.advice.exception_handler.ECDException; import io.jsonwebtoken.Claims; @@ -25,6 +27,8 @@ public class JwtAuthenticationUtil { private JwtUtil jwtUtil; @Autowired private RedisTemplate redisTemplate; + @Autowired + private UserLoginRepo userLoginRepo; private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { @@ -72,6 +76,10 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { // Check if user data is present in Redis Users user = getUserFromCache(userId); + if (user == null) { + // If not in Redis, fetch from DB and cache the result + user = fetchUserFromDB(userId); + } if (user == null) { throw new Exception("Invalid User ID."); } @@ -88,11 +96,31 @@ private Users getUserFromCache(String userId) { Users user = (Users) redisTemplate.opsForValue().get(redisKey); if (user == null) { - logger.warn("User not found in Redis."); + logger.warn("User not found in Redis. Will try to fetch from DB."); } else { logger.info("User fetched successfully from Redis."); } return user; // Returns null if not found } + + private Users fetchUserFromDB(String userId) { + // This method will only be called if the user is not found in Redis. + String redisKey = "user_" + userId; // Redis key format + + // Fetch user from DB + Users user = userLoginRepo.getUserByUserID(Long.parseLong(userId)); + + if (user != null) { + // Cache the user in Redis for future requests (cache for 30 minutes) + redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES); + + // Log that the user has been stored in Redis + logger.info("User stored in Redis with key: " + redisKey); + } else { + logger.warn("User not found for userId: " + userId); + } + + return user; + } }