From 0710f81a402c493885af9e1405effd33b700cff2 Mon Sep 17 00:00:00 2001
From: ravishanigarapu <133210792+ravishanigarapu@users.noreply.github.com>
Date: Thu, 7 Aug 2025 10:28:37 +0530
Subject: [PATCH 1/4] fix: Handled Improper session managemant (#108)
* AMM-1217
* removed unused imports
* removed unused imports
* AMM-1252
* swagger changes
* bug(Identity-API) Edit family tagging null condition added
* Jwttoken implementation and Crossorigin changes.
* code rabbit comments addressed
* coderabbitai comments addressed
* coderabbit commments addressed
* code optimised
* redis runtime issuefixed
* Coderabbit changes
* removed unused method
* Coderabbit comments addressed
---
pom.xml | 20 +++
src/main/environment/1097_ci.properties | 4 +-
src/main/environment/1097_docker.properties | 4 +-
src/main/environment/1097_example.properties | 3 +-
src/main/environment/common_ci.properties | 4 +-
src/main/environment/common_docker.properties | 4 +-
.../environment/common_example.properties | 3 +-
.../common/identity/config/CorsConfig.java | 23 +++
.../controller/IdentityController.java | 22 ---
.../FamilyTaggingController.java | 8 -
.../controller/version/VersionController.java | 2 -
.../com/iemr/common/identity/domain/User.java | 145 +++++++++++++++
.../common/identity/utils/CookieUtil.java | 28 +++
.../common/identity/utils/FilterConfig.java | 26 +++
.../identity/utils/JwtAuthenticationUtil.java | 115 ++++++++++++
.../utils/JwtUserIdValidationFilter.java | 154 ++++++++++++++++
.../iemr/common/identity/utils/JwtUtil.java | 168 ++++++++++++++++++
.../common/identity/utils/TokenDenylist.java | 72 ++++++++
.../identity/utils/UserAgentContext.java | 20 +++
.../exception/TokenDenylistException.java | 17 ++
.../AuthorizationHeaderRequestWrapper.java | 44 +++++
.../utils/http/HTTPRequestInterceptor.java | 2 +-
.../identity/utils/redis/RedisConfig.java | 36 ++++
src/main/resources/application.properties | 14 +-
24 files changed, 887 insertions(+), 51 deletions(-)
create mode 100644 src/main/java/com/iemr/common/identity/config/CorsConfig.java
create mode 100644 src/main/java/com/iemr/common/identity/domain/User.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/CookieUtil.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/FilterConfig.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/JwtUtil.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/TokenDenylist.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/UserAgentContext.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/exception/TokenDenylistException.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/http/AuthorizationHeaderRequestWrapper.java
create mode 100644 src/main/java/com/iemr/common/identity/utils/redis/RedisConfig.java
diff --git a/pom.xml b/pom.xml
index c5e15820..a9499b72 100644
--- a/pom.xml
+++ b/pom.xml
@@ -220,6 +220,26 @@
spring-web
6.1.12
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.12.6
+
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.12.6
+ runtime
+
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.12.6
+ runtime
+
diff --git a/src/main/environment/1097_ci.properties b/src/main/environment/1097_ci.properties
index a2b79037..fba22112 100644
--- a/src/main/environment/1097_ci.properties
+++ b/src/main/environment/1097_ci.properties
@@ -20,4 +20,6 @@ tm-url=@TM_API@
fhir-url=@FHIR_API@
# Redis Config
-spring.redis.host=@env.REDIS_HOST@
\ No newline at end of file
+spring.redis.host=@env.REDIS_HOST@
+
+cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@
diff --git a/src/main/environment/1097_docker.properties b/src/main/environment/1097_docker.properties
index 5510dfce..471665aa 100644
--- a/src/main/environment/1097_docker.properties
+++ b/src/main/environment/1097_docker.properties
@@ -19,4 +19,6 @@ tm-url=${TM_API}
fhir-url=${FHIR_API}
# Redis Config
-spring.redis.host=${REDIS_HOST}
\ No newline at end of file
+spring.redis.host=${REDIS_HOST}
+
+cors.allowed-origins=${CORS_ALLOWED_ORIGINS}
diff --git a/src/main/environment/1097_example.properties b/src/main/environment/1097_example.properties
index 9eeee5c4..d1f66965 100644
--- a/src/main/environment/1097_example.properties
+++ b/src/main/environment/1097_example.properties
@@ -17,4 +17,5 @@ tm-url=http://localhost:8089/
fhir-url=http://localhost:8093/
# Redis Config
-spring.redis.host=localhost
\ No newline at end of file
+spring.redis.host=localhost
+cors.allowed-origins=http://localhost:*
diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties
index debf33c4..ab01423a 100644
--- a/src/main/environment/common_ci.properties
+++ b/src/main/environment/common_ci.properties
@@ -20,4 +20,6 @@ tm-url=@TM_API@
fhir-url=@FHIR_API@
# Redis Config
-spring.redis.host=@env.REDIS_HOST@
\ No newline at end of file
+spring.redis.host=@env.REDIS_HOST@
+
+cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@
diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties
index 4409906e..90942c28 100644
--- a/src/main/environment/common_docker.properties
+++ b/src/main/environment/common_docker.properties
@@ -20,4 +20,6 @@ tm-url=${TM_API}
fhir-url=${FHIR_API}
# Redis Config
-spring.redis.host=${REDIS_HOST}
\ No newline at end of file
+spring.redis.host=${REDIS_HOST}
+
+cors.allowed-origins=${CORS_ALLOWED_ORIGINS}
diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties
index ca58c85c..ad15db00 100644
--- a/src/main/environment/common_example.properties
+++ b/src/main/environment/common_example.properties
@@ -16,4 +16,5 @@ tm-url=http://localhost:8089/
fhir-url=http://localhost:8093/
# Redis Config
-spring.redis.host=localhost
\ No newline at end of file
+spring.redis.host=localhost
+cors.allowed-origins=http://localhost:*
diff --git a/src/main/java/com/iemr/common/identity/config/CorsConfig.java b/src/main/java/com/iemr/common/identity/config/CorsConfig.java
new file mode 100644
index 00000000..d52f7e35
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/config/CorsConfig.java
@@ -0,0 +1,23 @@
+package com.iemr.common.identity.config;
+
+import java.util.Arrays;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class CorsConfig implements WebMvcConfigurer {
+ @Value("${cors.allowed-origins}")
+ private String allowedOrigins;
+
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**").allowedOriginPatterns(
+ allowedOrigins != null && !allowedOrigins.trim().isEmpty() ? Arrays.stream(allowedOrigins.split(","))
+ .map(String::trim).filter(s -> !s.isEmpty()).toArray(String[]::new) : new String[0])
+ .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").allowedHeaders("*")
+ .exposedHeaders("Authorization", "Jwttoken").allowCredentials(true).maxAge(3600);
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/controller/IdentityController.java b/src/main/java/com/iemr/common/identity/controller/IdentityController.java
index 03484813..4ac603ae 100644
--- a/src/main/java/com/iemr/common/identity/controller/IdentityController.java
+++ b/src/main/java/com/iemr/common/identity/controller/IdentityController.java
@@ -33,7 +33,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -83,7 +82,6 @@ public class IdentityController {
@Autowired
IdentityMapper mapper;
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Get beneficiaries by advance search")
@PostMapping(path = "/advanceSearch", headers = "Authorization")
public String getBeneficiaries(
@@ -112,7 +110,6 @@ public String getBeneficiaries(
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Search beneficiary based on beneficiary registration id")
@PostMapping(path = "/getByBenRegId", headers = "Authorization")
public String getBeneficiariesByBeneficiaryRegId(
@@ -137,7 +134,6 @@ public String getBeneficiariesByBeneficiaryRegId(
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Search identity based on beneficiary registration id")
@PostMapping(path = "/getByBenId", headers = "Authorization")
public String getBeneficiariesByBeneficiaryId(
@@ -172,7 +168,6 @@ public String getBeneficiariesByBeneficiaryId(
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Search beneficiary based on phone number")
@PostMapping(path = "/getByPhoneNum", headers = "Authorization")
public String getBeneficiariesByPhoneNum(
@@ -203,7 +198,6 @@ public String getBeneficiariesByPhoneNum(
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Search beneficiary based on health ID / ABHA Address")
@PostMapping(path = "/getByAbhaAddress", headers = "Authorization")
public String searhBeneficiaryByABHAAddress(
@@ -235,7 +229,6 @@ public String searhBeneficiaryByABHAAddress(
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Search beneficiary based on health ID number / ABHA ID number")
@PostMapping(path = "/getByAbhaIdNo", headers = "Authorization")
public String searhBeneficiaryByABHAIdNo(
@@ -267,7 +260,6 @@ public String searhBeneficiaryByABHAIdNo(
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Search beneficiary based on family id")
@PostMapping(path = "/searchByFamilyId", headers = "Authorization")
public String searhBeneficiaryByFamilyId(
@@ -297,7 +289,6 @@ public String searhBeneficiaryByFamilyId(
}
// search beneficiary by lastModDate and districtID
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary ="Search beneficiary by villageId and last modified date-time")
@PostMapping(path = "/searchByVillageIdAndLastModifiedDate")
public String searchBeneficiaryByVillageIdAndLastModDate(
@@ -322,7 +313,6 @@ public String searchBeneficiaryByVillageIdAndLastModDate(
return response;
}
// search beneficiary by lastModDate and districtID
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary ="Get count of beneficiary by villageId and last modified date-time")
@PostMapping(path = "/countBenByVillageIdAndLastModifiedDate")
public String countBeneficiaryByVillageIdAndLastModDate(
@@ -342,7 +332,6 @@ public String countBeneficiaryByVillageIdAndLastModDate(
}
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Search beneficiary based on government identity number")
@PostMapping(path = "/searhByGovIdentity", headers = "Authorization")
public String searhBeneficiaryByGovIdentity(
@@ -376,7 +365,6 @@ public String searhBeneficiaryByGovIdentity(
* @param identityEditData
* @return
*/
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Edit identity by agent")
@PostMapping(path = "/edit", headers = "Authorization")
public String editIdentity(@Param(value = "{\r\n" + " \"eventTypeName\": \"String\",\r\n"
@@ -508,7 +496,6 @@ public String editIdentity(@Param(value = "{\r\n" + " \"eventTypeName\": \"Stri
* @param identityData
* @return
*/
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Create identity by agent")
@PostMapping(path = "/create", headers = "Authorization")
public String createIdentity(@Param(value = "{\r\n" + " \"eventTypeName\": \"String\",\r\n"
@@ -615,7 +602,6 @@ public String createIdentity(@Param(value = "{\r\n" + " \"eventTypeName\": \"St
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Reserve identity by agent")
@PostMapping(path = "/reserve", headers = "Authorization")
public String reserveIdentity(@RequestBody String reserveIdentity) {
@@ -635,7 +621,6 @@ public String reserveIdentity(@RequestBody String reserveIdentity) {
return response;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Unreserve identity by agent")
@PostMapping(path = "/unreserve", headers = "Authorization")
public String unreserveIdentity(@RequestBody String unreserve) {
@@ -661,7 +646,6 @@ public String unreserveIdentity(@RequestBody String unreserve) {
* @param benRegIds
* @return
*/
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Get beneficiaries partial details by beneficiary registration id list")
@PostMapping(path = "/getByPartialBenRegIdList", headers = "Authorization")
public String getPartialBeneficiariesByBenRegIds(
@@ -693,7 +677,6 @@ public String getPartialBeneficiariesByBenRegIds(
* @param benRegIds
* @return
*/
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Get beneficiaries by beneficiary registration id")
@PostMapping(path = "/getByBenRegIdList", headers = "Authorization")
public String getBeneficiariesByBenRegIds(
@@ -792,7 +775,6 @@ public String getJsonAsString(Object obj) {
return sb.toString();
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Get finite beneficiaries")
@PostMapping(path = "/finiteSearch", headers = "Authorization")
public String getFiniteBeneficiaries(@RequestBody String searchFilter) {
@@ -816,7 +798,6 @@ public String getFiniteBeneficiaries(@RequestBody String searchFilter) {
}
// New API for getting beneficiary image only.
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Get beneficiary image by beneficiary registration id")
@PostMapping(path = "/benImageByBenRegID", headers = "Authorization")
public String getBeneficiaryImageByBenRegID(@RequestBody String identityData) {
@@ -830,7 +811,6 @@ public String getBeneficiaryImageByBenRegID(@RequestBody String identityData) {
return benImage;
}
- @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Edit education or community by agent")
@PostMapping(path = "/editEducationOrCommunity", headers = "Authorization")
public String editIdentityEducationOrCommunity(@Param(value = "{\r\n"
@@ -957,7 +937,6 @@ public String editIdentityEducationOrCommunity(@Param(value = "{\r\n"
}
}
- @CrossOrigin()
@Operation(summary = "Check available beneficary id in local server")
@GetMapping(path = "/checkAvailablBenIDLocalServer", headers = "Authorization")
public String checkAvailablBenIDLocalServer() {
@@ -972,7 +951,6 @@ public String checkAvailablBenIDLocalServer() {
return response.toString();
}
- // @CrossOrigin(origins = { "*commonapi*" })
@Operation(summary = "Save server generated beneficiary ID & beneficiary registration ID to local server")
@PostMapping(path = "/saveGeneratedBenIDToLocalServer", headers = "Authorization", consumes = "application/json", produces = "application/json")
public String saveGeneratedBenIDToLocalServer(
diff --git a/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java b/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java
index b1f117c7..19323611 100644
--- a/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java
+++ b/src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java
@@ -24,7 +24,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -35,7 +34,6 @@
import io.swagger.v3.oas.annotations.Operation;
-@CrossOrigin
@RestController
@RequestMapping({ "/family" })
public class FamilyTaggingController {
@@ -43,7 +41,6 @@ public class FamilyTaggingController {
@Autowired
private FamilyTagService familyTagService;
- @CrossOrigin()
@Operation(summary = "Create and modify family tagging")
@PostMapping(value = { "/addTag" }, consumes = "application/json", produces = "application/json")
public String saveFamilyTagging(@RequestBody String comingReq) {
@@ -59,7 +56,6 @@ public String saveFamilyTagging(@RequestBody String comingReq) {
return response.toString();
}
- @CrossOrigin()
@Operation(summary = "Create family")
@PostMapping(value = { "/createFamily" }, consumes = "application/json", produces = "application/json")
public String createFamily(@RequestBody String comingReq) {
@@ -75,7 +71,6 @@ public String createFamily(@RequestBody String comingReq) {
return response.toString();
}
- @CrossOrigin()
@Operation(summary = "Search family")
@PostMapping(value = { "/searchFamily" }, consumes = "application/json", produces = "application/json")
public String searchFamily(@RequestBody String comingReq) {
@@ -91,7 +86,6 @@ public String searchFamily(@RequestBody String comingReq) {
return response.toString();
}
- @CrossOrigin()
@Operation(summary = "Get family members details")
@PostMapping(value = { "/getFamilyDetails" }, consumes = "application/json", produces = "application/json")
public String getFamilyDatails(@RequestBody String comingReq) {
@@ -107,7 +101,6 @@ public String getFamilyDatails(@RequestBody String comingReq) {
return response.toString();
}
- @CrossOrigin()
@Operation(summary = "Untag beneficiary from a family")
@PostMapping(value = { "/untag" }, consumes = "application/json", produces = "application/json")
public String untagFamily(@RequestBody String comingReq) {
@@ -123,7 +116,6 @@ public String untagFamily(@RequestBody String comingReq) {
return response.toString();
}
- @CrossOrigin()
@Operation(summary = "Edit beneficiary family details")
@PostMapping(value = { "/editFamilyTagging" }, consumes = "application/json", produces = "application/json")
public String editFamilyDetails(@RequestBody String comingReq) {
diff --git a/src/main/java/com/iemr/common/identity/controller/version/VersionController.java b/src/main/java/com/iemr/common/identity/controller/version/VersionController.java
index fdf973cd..4435c3db 100644
--- a/src/main/java/com/iemr/common/identity/controller/version/VersionController.java
+++ b/src/main/java/com/iemr/common/identity/controller/version/VersionController.java
@@ -28,7 +28,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -41,7 +40,6 @@ public class VersionController {
private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
- @CrossOrigin()
@Operation(summary = "Get version information")
@GetMapping(value = "/version",consumes = "application/json", produces = "application/json")
public String versionInformation() {
diff --git a/src/main/java/com/iemr/common/identity/domain/User.java b/src/main/java/com/iemr/common/identity/domain/User.java
new file mode 100644
index 00000000..59fad34b
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/domain/User.java
@@ -0,0 +1,145 @@
+package com.iemr.common.identity.domain;
+
+import java.sql.Timestamp;
+import java.time.LocalDate;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+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;
+@Entity
+@Table(name = "m_User",schema = "db_iemr")
+@Data
+public class User {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ @Expose
+ @Column(name="UserID")
+ private Integer userID;
+ @Expose
+ @Column(name="TitleID")
+ private Integer 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 Integer maritalStatusID;
+ @Expose
+ @Column(name="DesignationID")
+ private Integer designationID;
+
+ @Column(name="AadhaarNo")
+ private String aadhaarNo;
+ @Column(name="PAN")
+ private String pAN;
+ @Expose
+ @Column(name="DOB")
+ private LocalDate dOB;
+ @Expose
+ @Column(name="DOJ")
+ private LocalDate dOJ;
+ @Expose
+ @Column(name="QualificationID")
+ private Integer qualificationID;
+ @Expose
+ @Column(name="HealthProfessionalID")
+ private String healthProfessionalID;
+ @Expose
+ @Column(name="UserName")
+ private String userName;
+ @JsonIgnore
+ @Column(name="Password")
+ private String password;
+ @Expose
+ @Column(name="IsExternal")
+ private Boolean isExternal;
+ @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 Integer 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",insertable = false, updatable = true)
+ private Boolean deleted;
+ @Expose
+ @Column(name="CreatedBy")
+ private String createdBy;
+ @Expose
+ @Column(name="EmployeeID")
+ private String employeeID;
+ @Expose
+ @Column(name="CreatedDate",insertable = false, updatable = false)
+ private Timestamp createdDate;
+ @Expose
+ @Column(name="ModifiedBy")
+ private String modifiedBy;
+ @Expose
+ @Column(name="LastModDate",insertable = false, updatable = false)
+ private Timestamp lastModDate;
+
+ @Expose
+ @Column(name="Remarks")
+ private String remarks;
+
+ @Expose
+ @Column(name="ContactNo")
+ private String contactNo;
+
+
+ @Expose
+ @Column(name="IsProviderAdmin")
+ private Boolean isProviderAdmin;
+
+ @Expose
+ @Column(name="ServiceProviderID")
+ private Integer serviceProviderID;
+
+
+
+ @Expose
+ @Column(name = "failed_attempt", insertable = false)
+ private Integer failedAttempt;
+ public User() {
+ // TODO Auto-generated constructor stub
+ }
+
+ public User(Integer userID, String userName) {
+ // TODO Auto-generated constructor stub
+ this.userID=userID;
+ this.userName=userName;
+ }
+
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/CookieUtil.java b/src/main/java/com/iemr/common/identity/utils/CookieUtil.java
new file mode 100644
index 00000000..84f54526
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/CookieUtil.java
@@ -0,0 +1,28 @@
+package com.iemr.common.identity.utils;
+
+import java.util.Optional;
+
+import org.springframework.stereotype.Service;
+
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+
+@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 String getJwtTokenFromCookie(HttpServletRequest request) {
+ return getCookieValue(request, "Jwttoken").orElse(null);
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/FilterConfig.java b/src/main/java/com/iemr/common/identity/utils/FilterConfig.java
new file mode 100644
index 00000000..e13b8b4e
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/FilterConfig.java
@@ -0,0 +1,26 @@
+package com.iemr.common.identity.utils;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
+
+@Configuration
+public class FilterConfig {
+ @Value("${cors.allowed-origins}")
+ private String allowedOrigins;
+
+ @Bean
+ public FilterRegistrationBean jwtUserIdValidationFilter(
+ JwtAuthenticationUtil jwtAuthenticationUtil, CookieUtil cookieUtil) {
+ FilterRegistrationBean registrationBean = new FilterRegistrationBean<>();
+
+ JwtUserIdValidationFilter filter = new JwtUserIdValidationFilter(jwtAuthenticationUtil, allowedOrigins, cookieUtil);
+ registrationBean.setFilter(filter);
+ registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
+ registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints
+ return registrationBean;
+ }
+
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java
new file mode 100644
index 00000000..8f379d14
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java
@@ -0,0 +1,115 @@
+package com.iemr.common.identity.utils;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+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.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import com.iemr.common.identity.domain.User;
+import com.iemr.common.identity.exception.IEMRException;
+
+import io.jsonwebtoken.Claims;
+import jakarta.servlet.http.HttpServletRequest;
+
+@Component
+public class JwtAuthenticationUtil {
+ private CookieUtil cookieUtil;
+ private JwtUtil jwtUtil;
+ private RedisTemplate redisTemplate;
+
+ private JdbcTemplate jdbcTemplate;
+
+ 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 IEMRException {
+ try {
+ Claims claims = jwtUtil.validateToken(jwtToken);
+ if (claims == null) {
+ throw new IEMRException("Invalid JWT token.");
+ }
+ String userId = claims.get("userId", String.class);
+ User user = getUserFromCache(userId);
+ if (user == null) {
+ user = fetchUserFromDB(userId);
+ }
+ if (user == null) {
+ throw new IEMRException("Invalid User ID.");
+ }
+
+ return true; // Valid userId and JWT token
+ } catch (Exception e) {
+ logger.error("Validation failed: " + e.getMessage(), e);
+ throw new IEMRException("Validation error: " + e.getMessage(), e);
+ }
+ }
+
+ private User getUserFromCache(String userId) {
+ String redisKey = "user_" + userId; // The Redis key format
+ User user = (User) redisTemplate.opsForValue().get(redisKey);
+
+ if (user == null) {
+ 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 User fetchUserFromDB(String userId) {
+ String redisKey = "user_" + userId; // Redis key format
+ List users = jdbcTemplate.query("SELECT * FROM db_iemr.m_user WHERE UserID = ? AND Deleted = false",
+ new BeanPropertyRowMapper<>(User.class), userId);
+
+ if (users.isEmpty()) {
+ logger.warn("User not found for userId: " + userId);
+ return null;
+ }
+
+ User user = users.get(0);
+ redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES);
+ logger.info("User stored in Redis with key: " + redisKey);
+ return user;
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java
new file mode 100644
index 00000000..a030ab31
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java
@@ -0,0 +1,154 @@
+package com.iemr.common.identity.utils;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.iemr.common.identity.utils.http.AuthorizationHeaderRequestWrapper;
+
+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;
+
+public class JwtUserIdValidationFilter implements Filter {
+ private final JwtAuthenticationUtil jwtAuthenticationUtil;
+ private final CookieUtil cookieUtil;
+ private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+ private final String allowedOrigins;
+
+ public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil, String allowedOrigins, CookieUtil cookieUtil) {
+ this.jwtAuthenticationUtil = jwtAuthenticationUtil;
+ this.allowedOrigins = allowedOrigins;
+ this.cookieUtil = cookieUtil;
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+ handleCorsHeaders(request, response);
+
+ if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
+ logger.info("OPTIONS request - skipping JWT validation");
+ response.setStatus(HttpServletResponse.SC_OK);
+ return;
+ }
+ String path = request.getRequestURI();
+ logger.info("JwtUserIdValidationFilter invoked for path: " + path);
+
+ // Log cookies for debugging
+ Cookie[] cookies = request.getCookies();
+ if (cookies != null) {
+ for (Cookie cookie : cookies) {
+ if ("userId".equalsIgnoreCase(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
+ logger.info("JWT token from header: ");
+
+ try {
+ String jwtFromCookie = getJwtTokenFromCookies(request);
+ String jwtFromHeader = request.getHeader("JwtToken");
+ String authHeader = request.getHeader("Authorization");
+ String jwtToken = jwtFromCookie != null ? jwtFromCookie : jwtFromHeader;
+ if (jwtToken != null) {
+ logger.info("Validating JWT token from cookie");
+ if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken)) {
+ AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper(
+ request, "");
+ filterChain.doFilter(authorizationHeaderRequestWrapper, servletResponse);
+ return;
+ }
+ } else {
+ String userAgent = request.getHeader("User-Agent");
+ logger.info("User-Agent: " + userAgent);
+ if (userAgent != null && isMobileClient(userAgent) && authHeader != null) {
+ try {
+ logger.info("Common-API incoming userAget : " + userAgent);
+ UserAgentContext.setUserAgent(userAgent);
+ filterChain.doFilter(servletRequest, servletResponse);
+ } finally {
+ UserAgentContext.clear();
+ }
+ return;
+ }
+ }
+
+ logger.warn("No valid authentication token found");
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Invalid or missing token");
+ } catch (Exception e) {
+ logger.error("Authorization error: ", e);
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage());
+ }
+ }
+
+ private void handleCorsHeaders(HttpServletRequest request, HttpServletResponse response) {
+ String origin = request.getHeader("Origin");
+
+ logger.debug("Incoming Origin: {}", origin);
+ logger.debug("Allowed Origins Configured: {}", allowedOrigins);
+
+ if (origin != null && isOriginAllowed(origin)) {
+ response.setHeader("Access-Control-Allow-Origin", origin);
+ response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+ response.setHeader("Access-Control-Allow-Headers",
+ "Authorization, Content-Type, Accept, JwtToken, Jwttoken");
+ response.setHeader("Vary", "Origin");
+ response.setHeader("Access-Control-Allow-Credentials", "true");
+ } else {
+ logger.warn("Origin [{}] is NOT allowed. CORS headers NOT added.", origin);
+ }
+
+ }
+
+ private boolean isOriginAllowed(String origin) {
+ if (origin == null || allowedOrigins == null || allowedOrigins.trim().isEmpty()) {
+ logger.warn("No allowed origins configured or origin is null");
+ return false;
+ }
+
+ return Arrays.stream(allowedOrigins.split(",")).map(String::trim).anyMatch(pattern -> {
+ String regex = pattern.replace(".", "\\.").replace("*", ".*").replace("http://localhost:.*",
+ "http://localhost:\\d+"); // special case for wildcard port
+
+ boolean matched = origin.matches(regex);
+ return matched;
+ });
+ }
+
+ private boolean isMobileClient(String userAgent) {
+ if (userAgent == null)
+ return false;
+ userAgent = userAgent.toLowerCase();
+ return userAgent.contains("okhttp"); // iOS (custom clients)
+ }
+
+ private String getJwtTokenFromCookies(HttpServletRequest request) {
+ return cookieUtil.getJwtTokenFromCookie(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
+ cookie.setAttribute("SameSite", "Strict");
+ response.addCookie(cookie);
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/JwtUtil.java b/src/main/java/com/iemr/common/identity/utils/JwtUtil.java
new file mode 100644
index 00000000..5d3dc830
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/JwtUtil.java
@@ -0,0 +1,168 @@
+package com.iemr.common.identity.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Date;
+import java.util.UUID;
+import java.util.function.Function;
+
+import javax.crypto.SecretKey;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.MalformedJwtException;
+import io.jsonwebtoken.UnsupportedJwtException;
+import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.SignatureException;
+@Component
+public class JwtUtil {
+ @Value("${jwt.secret}")
+ private String SECRET_KEY;
+
+ @Value("${jwt.access.expiration}")
+ private long ACCESS_EXPIRATION_TIME;
+
+ @Value("${jwt.refresh.expiration}")
+ private long REFRESH_EXPIRATION_TIME;
+
+ @Autowired
+ private TokenDenylist tokenDenylist;
+
+ private SecretKey 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(StandardCharsets.UTF_8));
+ }
+
+ /**
+ * Generate an access token.
+ *
+ * @param username the username of the user
+ * @param userId the user ID
+ * @return the generated JWT access token
+ */
+ public String generateToken(String username, String userId) {
+ return buildToken(username, userId, "access", ACCESS_EXPIRATION_TIME);
+ }
+
+ /**
+ * Generate a refresh token.
+ *
+ * @param username the username of the user
+ * @param userId the user ID
+ * @return the generated JWT refresh token
+ */
+ public String generateRefreshToken(String username, String userId) {
+ return buildToken(username, userId, "refresh", REFRESH_EXPIRATION_TIME);
+ }
+
+ /**
+ * Build a JWT token with the specified parameters.
+ *
+ * @param username the username of the user
+ * @param userId the user ID
+ * @param tokenType the type of the token (access or refresh)
+ * @param expiration the expiration time of the token in milliseconds
+ * @return the generated JWT token
+ */
+ private String buildToken(String username, String userId, String tokenType, long expiration) {
+ if (username == null || username.trim().isEmpty()) {
+ throw new IllegalArgumentException("Username cannot be null or empty");
+ }
+ if (userId == null || userId.trim().isEmpty()) {
+ throw new IllegalArgumentException("User ID cannot be null or empty");
+ }
+ return Jwts.builder().subject(username).claim("userId", userId).claim("token_type", tokenType)
+ .id(UUID.randomUUID().toString()).issuedAt(new Date())
+ .expiration(new Date(System.currentTimeMillis() + expiration)).signWith(getSigningKey()).compact();
+ }
+
+ /**
+ * Validate the JWT token, checking if it is expired and if it's blacklisted
+ * @param token the JWT token
+ * @return Claims if valid, null if invalid (expired or denylisted)
+ */
+ public Claims validateToken(String token) {
+ try {
+ Claims claims = Jwts.parser().verifyWith(getSigningKey()).build().parseSignedClaims(token).getPayload();
+ String jti = claims.getId();
+
+ // Check if token is denylisted (only if jti exists)
+ if (jti != null && tokenDenylist.isTokenDenylisted(jti)) {
+ return null;
+ }
+ return claims;
+ } catch (ExpiredJwtException ex) {
+
+ return null; // Token is expired, so return null
+ } catch (UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException ex) {
+ return null; // Return null for any other JWT-related issue (invalid format, bad signature, etc.)
+ }
+ }
+
+ /**
+ * Extract claims from the token
+ * @param token the JWT token
+ * @return all claims from the token
+ */
+ public Claims getAllClaimsFromToken(String token) {
+ Claims claims = validateToken(token);
+ if (claims == null) {
+ throw new IllegalArgumentException("Invalid or denylisted token");
+ }
+ return claims;
+
+ }
+
+ /**
+ * Extract a specific claim from the token using a function
+ * @param token the JWT token
+ * @param claimsResolver the function to extract the claim
+ * @param the type of the claim
+ * @return the extracted claim
+ */
+ public T getClaimFromToken(String token, Function claimsResolver) {
+ final Claims claims = getAllClaimsFromToken(token);
+ return claimsResolver.apply(claims);
+ }
+
+ /**
+ * Get the JWT ID (JTI) from the token
+ * @param token the JWT token
+ * @return the JWT ID
+ */
+ public String getJtiFromToken(String token) {
+ return getAllClaimsFromToken(token).getId();
+ }
+
+ /**
+ * Get the username from the token
+ * @param token the JWT token
+ * @return the username
+ */
+ public String getUsernameFromToken(String token) {
+ return getAllClaimsFromToken(token).getSubject();
+ }
+
+ /**
+ * Get the user ID from the token
+ * @param token the JWT token
+ * @return the user ID
+ */
+ public String getUserIdFromToken(String token) {
+ return getAllClaimsFromToken(token).get("userId", String.class);
+ }
+
+ /**
+ * Get the expiration time of the refresh token
+ * @return the expiration time in milliseconds
+ */
+ public long getRefreshTokenExpiration() {
+ return REFRESH_EXPIRATION_TIME;
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/TokenDenylist.java b/src/main/java/com/iemr/common/identity/utils/TokenDenylist.java
new file mode 100644
index 00000000..1248f478
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/TokenDenylist.java
@@ -0,0 +1,72 @@
+package com.iemr.common.identity.utils;
+
+import java.util.concurrent.TimeUnit;
+
+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.stereotype.Component;
+
+import com.iemr.common.identity.utils.exception.TokenDenylistException;
+@Component
+public class TokenDenylist {
+ private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
+
+ private static final String PREFIX = "denied_";
+
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ private String getKey(String jti) {
+ return PREFIX + jti;
+ }
+
+ public void addTokenToDenylist(String jti, Long expirationTime) {
+ if (jti == null || jti.trim().isEmpty()) {
+ logger.warn("Attempted to add null or empty jti to denylist");
+ return;
+ }
+ if (expirationTime == null || expirationTime <= 0) {
+ logger.error("Invalid expiration time for jti: {}", jti);
+ throw new IllegalArgumentException("Expiration time must be positive");
+ }
+ try {
+ String key = getKey(jti); // Use helper method to get the key
+ redisTemplate.opsForValue().set(key, " ", expirationTime, TimeUnit.MILLISECONDS);
+ logger.debug("Added jti to denylist: {}", jti);
+ } catch (Exception e) {
+ logger.error("Failed to denylist token with jti: {}", jti, e);
+ throw new TokenDenylistException("Failed to denylist token", e);
+ }
+ }
+
+ public boolean isTokenDenylisted(String jti) {
+ if (jti == null || jti.trim().isEmpty()) {
+ return false;
+ }
+ try {
+ String key = getKey(jti); // Use helper method to get the key
+ return Boolean.TRUE.equals(redisTemplate.hasKey(key));
+ } catch (Exception e) {
+ logger.error("Failed to check denylist status for jti: " + jti, e);
+ throw new TokenDenylistException("Unable to verify token denylist status", e);
+ }
+ }
+
+ // Remove a token's jti from the denylist (Redis)
+ public void removeTokenFromDenylist(String jti) {
+ if (jti != null && !jti.trim().isEmpty()) {
+ try {
+ String key = getKey(jti);
+ redisTemplate.delete(key);
+ logger.debug("Removed jti from denylist: {}", jti);
+ } catch (Exception e) {
+ logger.error("Failed to remove token from denylist with jti: {}", jti, e);
+ throw new TokenDenylistException("Failed to remove token from denylist", e);
+ }
+ } else {
+ logger.warn("Attempted to remove null or empty jti from denylist");
+ }
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/UserAgentContext.java b/src/main/java/com/iemr/common/identity/utils/UserAgentContext.java
new file mode 100644
index 00000000..59cc804b
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/UserAgentContext.java
@@ -0,0 +1,20 @@
+package com.iemr.common.identity.utils;
+
+public class UserAgentContext {
+ private static final ThreadLocal userAgentHolder = new ThreadLocal<>();
+
+ public static void setUserAgent(String userAgent) {
+ if (userAgent != null && userAgent.trim().isEmpty()) {
+ userAgent = null; // Treat empty strings as null
+ }
+ userAgentHolder.set(userAgent);
+ }
+
+ public static String getUserAgent() {
+ return userAgentHolder.get();
+ }
+
+ public static void clear() {
+ userAgentHolder.remove();
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/exception/TokenDenylistException.java b/src/main/java/com/iemr/common/identity/utils/exception/TokenDenylistException.java
new file mode 100644
index 00000000..d2d16985
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/exception/TokenDenylistException.java
@@ -0,0 +1,17 @@
+package com.iemr.common.identity.utils.exception;
+
+public class TokenDenylistException extends RuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ public TokenDenylistException(String message) {
+ super(message);
+ }
+
+ public TokenDenylistException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TokenDenylistException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/http/AuthorizationHeaderRequestWrapper.java b/src/main/java/com/iemr/common/identity/utils/http/AuthorizationHeaderRequestWrapper.java
new file mode 100644
index 00000000..bbbc3de7
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/http/AuthorizationHeaderRequestWrapper.java
@@ -0,0 +1,44 @@
+package com.iemr.common.identity.utils.http;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+
+public class AuthorizationHeaderRequestWrapper extends HttpServletRequestWrapper {
+ private final String Authorization;
+
+ public AuthorizationHeaderRequestWrapper(HttpServletRequest request, String authHeaderValue) {
+ super(request);
+ this.Authorization = authHeaderValue != null ? authHeaderValue : "";
+ }
+
+ @Override
+ public String getHeader(String name) {
+ if ("Authorization".equalsIgnoreCase(name)) {
+ return Authorization;
+ }
+ return super.getHeader(name);
+ }
+
+ @Override
+ public Enumeration getHeaders(String name) {
+ if ("Authorization".equalsIgnoreCase(name)) {
+ return Authorization != null ? Collections.enumeration(Collections.singletonList(Authorization))
+ : Collections.emptyEnumeration();
+ }
+ return super.getHeaders(name);
+ }
+
+ @Override
+ public Enumeration getHeaderNames() {
+ List names = Collections.list(super.getHeaderNames());
+ boolean hasAuth = names.stream().anyMatch(name -> "Authorization".equalsIgnoreCase(name));
+ if (!hasAuth) {
+ names.add("Authorization");
+ }
+ return Collections.enumeration(names);
+ }
+}
diff --git a/src/main/java/com/iemr/common/identity/utils/http/HTTPRequestInterceptor.java b/src/main/java/com/iemr/common/identity/utils/http/HTTPRequestInterceptor.java
index 865df356..7156102c 100644
--- a/src/main/java/com/iemr/common/identity/utils/http/HTTPRequestInterceptor.java
+++ b/src/main/java/com/iemr/common/identity/utils/http/HTTPRequestInterceptor.java
@@ -102,7 +102,7 @@ public void postHandle(HttpServletRequest request, HttpServletResponse response,
else
authorization = postAuth;
logger.debug("RequestURI::" + request.getRequestURI() + " || Authorization ::" + authorization);
- if (authorization != null) {
+ if (authorization != null && !authorization.isEmpty()) {
sessionObject.updateSessionObject(authorization, sessionObject.getSessionObject(authorization));
}
} catch (Exception e) {
diff --git a/src/main/java/com/iemr/common/identity/utils/redis/RedisConfig.java b/src/main/java/com/iemr/common/identity/utils/redis/RedisConfig.java
new file mode 100644
index 00000000..f4e3ffc7
--- /dev/null
+++ b/src/main/java/com/iemr/common/identity/utils/redis/RedisConfig.java
@@ -0,0 +1,36 @@
+package com.iemr.common.identity.utils.redis;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+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 org.springframework.session.data.redis.config.ConfigureRedisAction;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.iemr.common.identity.domain.User;
+
+@Configuration
+public class RedisConfig {
+ @Bean
+ public ConfigureRedisAction configureRedisAction() {
+ return ConfigureRedisAction.NO_OP;
+ }
+
+ @Bean
+ public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
+ RedisTemplate template = new RedisTemplate<>();
+ template.setConnectionFactory(factory);
+ Jackson2JsonRedisSerializer