Skip to content

Release 3.6.2#153

Open
snehar-nd wants to merge 61 commits into
mainfrom
release-3.6.2
Open

Release 3.6.2#153
snehar-nd wants to merge 61 commits into
mainfrom
release-3.6.2

Conversation

@snehar-nd

@snehar-nd snehar-nd commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

📋 Description

JIRA ID:

Moving 3.6.2 to main

✅ Type of Change

  • 🐞 Bug fix (non-breaking change which resolves an issue)
  • New feature (non-breaking change which adds functionality)
  • 🔥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 🛠 Refactor (change that is neither a fix nor a new feature)
  • ⚙️ Config change (configuration file or build script updates)
  • 📚 Documentation (updates to docs or readme)
  • 🧪 Tests (adding new or updating existing tests)
  • 🎨 UI/UX (changes that affect the user interface)
  • 🚀 Performance (improves performance)
  • 🧹 Chore (miscellaneous changes that don't modify src or test files)

ℹ️ Additional Information

Please describe how the changes were tested, and include any relevant screenshots, logs, or other information that provides additional context.

Summary by CodeRabbit

  • New Features
    • Added a health-check endpoint that reports service status and returns appropriate HTTP responses.
    • Added version details in a structured JSON format, including build and commit information.
    • Added support for ECG abnormal findings in lab results and master data.
  • Security
    • Added role-based access control across many application areas.
    • Improved authentication and authorization handling for requests and error responses.
  • Bug Fixes
    • Refined several workflow updates to preserve doctor signature status and reduce duplicate clinical observation entries.
    • Updated selected configuration endpoints and URL mappings for more specific routing.

5Amogh and others added 30 commits July 21, 2025 11:57
* story: amm-1668 task - 1754 dto updated

* story: amm-1668 task - 1754
…tData. (#96)

* Update version in pom.xml to 3.4.0

* story: amm-1668 task - 1754

* story: amm-1668 task - 1754 dto updated (#92)

* story: amm-1668 task - 1754 dto updated (#93)

* story: amm-1668 task - 1754 dto updated

* story: amm-1668 task - 1754

* fix: amm-1879 doctor signature was not coming for ncdcare

---------

Co-authored-by: Amoghavarsh <93114621+5Amogh@users.noreply.github.com>
Co-authored-by: 5Amogh <amoghavarsh@navadhiti.com>
fix: aam-1896 prescribed quantity was not coming in the casesheet
3.4.0 to 3.4.1
fix: amm-1919 fix for update doctor data for higher refferal data
Fix the WASA Issue : IDOR Vulnerability
* fix: amm-1927 res headers based on origin via allowed cors

* fix: amm-1927 coderabbit comments resolved

* localhost regex added

* Update regex pattern for localhost in interceptor
* fix: add @PreAuthorize to RBAC

* fix: wasa RBAC implementation

* fix: remove duplicate dependency

* fix: coderabbit comments

* fix: update role

* fix: enable the request matcher
vanitha1822 and others added 26 commits December 17, 2025 15:47
Implement Role-Based Access Control with JWT and Auth Integration
fix: amm-2063 added beneficiarytype but not reflecting in the DB level
Updating version from 3.6.0 to 3.6.2
fix: amm-2063 updated the updateBeneficiary flow
feat: amm-2175 dockendra ecg abnormal findings feature added
* fix: add labtech role for ecg controller

* fix: add role
* fix: add labtech role for ecg controller

* fix: add role

* fix: url issue in download document

* Remove authorization check from getKMFile method

Removed authorization check for getKMFile endpoint.
* fix: beneficiary update url

* fix: edit url

* fix: update the url
fix: 2346 handling duplicate entry of clinical observation
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds Spring Security role checks and authentication-based request handling across controllers, introduces health and version endpoints with git metadata generation, updates environment route values, and adds ECG abnormal findings support plus doctor-signature flag propagation through clinical flow updates.

Changes

Security and access control

Layer / File(s) Summary
Security plumbing and token lookup
pom.xml, src/main/java/com/iemr/tm/utils/*, src/main/java/com/iemr/tm/utils/http/*, src/main/java/com/iemr/tm/utils/mapper/*, src/main/java/com/iemr/tm/utils/redis/*
Adds Spring Security dependencies, token and role lookup helpers, Redis-backed role caching, custom auth handlers, CORS origin checks, and the security filter chain that installs the new role-authentication filter.
Clinical controller role checks
src/main/java/com/iemr/tm/controller/anc/*, src/main/java/com/iemr/tm/controller/cancerscreening/*, src/main/java/com/iemr/tm/controller/covid19/*, src/main/java/com/iemr/tm/controller/generalOPD/*, src/main/java/com/iemr/tm/controller/ncdCare/*, src/main/java/com/iemr/tm/controller/ncdscreening/*, src/main/java/com/iemr/tm/controller/nurse/vitals/*, src/main/java/com/iemr/tm/controller/patientApp/master/*, src/main/java/com/iemr/tm/controller/pnc/*, src/main/java/com/iemr/tm/controller/quickconsult/*
Adds @PreAuthorize role checks across the care-module controllers for save, get, and update endpoints.
Admin and specialist auth flows
src/main/java/com/iemr/tm/controller/common/main/*, src/main/java/com/iemr/tm/controller/common/master/*, src/main/java/com/iemr/tm/controller/registrar/main/*, src/main/java/com/iemr/tm/controller/labtechnician/*, src/main/java/com/iemr/tm/controller/location/*, src/main/java/com/iemr/tm/controller/report/*, src/main/java/com/iemr/tm/controller/snomedct/*, src/main/java/com/iemr/tm/controller/dataSyncActivity/*, src/main/java/com/iemr/tm/controller/dataSyncLayerCentral/*, src/main/java/com/iemr/tm/controller/foetalmonitor/*, src/main/java/com/iemr/tm/controller/login/*, src/main/java/com/iemr/tm/controller/teleconsultation/*, src/main/java/com/iemr/tm/controller/videoconsultationcontroller/*, src/main/environment/common_*.properties
Adds role checks to lookup, registrar, data-sync, and specialist controllers; teleconsultation, login, video, and worklist endpoints derive user identity from Authentication; beneficiary route config values are updated to the new create/edit paths.

Runtime support and utilities

Layer / File(s) Summary
Build metadata and health/version endpoints
pom.xml, src/main/environment/common_*.properties, src/main/java/com/iemr/tm/controller/health/*, src/main/java/com/iemr/tm/controller/version/*, src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java
Updates project versioning and git metadata generation, adds the /health and /version endpoints, allows those paths through the JWT filter, and changes the beneficiary route values in the environment property files.
Shared service utilities
src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java, src/main/java/com/iemr/tm/service/common/transaction/CommonNurseServiceImpl.java, src/main/java/com/iemr/tm/utils/StringListConverter.java
CommonServiceImpl changes OpenKM response handling, CommonNurseServiceImpl accepts additional frequency variants in dose calculations, and a List<String> JSON converter is added.

Clinical data and workflow updates

Layer / File(s) Summary
ECG abnormal findings exposure
src/main/java/com/iemr/tm/data/labModule/*, src/main/java/com/iemr/tm/repo/labModule/*, src/main/java/com/iemr/tm/service/labtechnician/*, src/main/java/com/iemr/tm/service/common/master/*, src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java
Adds the ECG abnormal-finding entity and repository, stores abnormal findings on lab results, exposes the lookup through the common master service/controller, and returns active findings from lab technician service.
Doctor workflow contracts
src/main/java/com/iemr/tm/data/benFlowStatus/*, src/main/java/com/iemr/tm/repo/benFlowStatus/*, src/main/java/com/iemr/tm/service/benFlowStatus/*, src/main/java/com/iemr/tm/service/common/transaction/CommonDoctorServiceImpl.java, src/main/java/com/iemr/tm/repo/nurse/ncdcare/NCDCareDiagnosisRepo.java, src/main/java/com/iemr/tm/data/ncdcare/NCDCareDiagnosis.java
Adds doctorSignatureFlag to beneficiary flow state, updates flow-table repository and service contracts to carry the flag, changes doctor workflow behavior around observations and referrals, and expands NCD care diagnosis projections and construction.
Doctor signature propagation
src/main/java/com/iemr/tm/service/anc/*, src/main/java/com/iemr/tm/service/cancerScreening/*, src/main/java/com/iemr/tm/service/covid19/*, src/main/java/com/iemr/tm/service/generalOPD/*, src/main/java/com/iemr/tm/service/ncdCare/*, src/main/java/com/iemr/tm/service/ncdscreening/*, src/main/java/com/iemr/tm/service/pnc/*, src/main/java/com/iemr/tm/service/quickConsultation/*
Reads doctorSignatureFlag from the incoming request payloads and passes it into the updated flow-table update methods in the doctor save/update paths.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant RoleAuthenticationFilter
  participant JwtUtil
  participant RedisStorage
  participant JwtAuthenticationUtil
  participant SecurityContextHolder
  Client->>RoleAuthenticationFilter: request
  RoleAuthenticationFilter->>JwtUtil: validate token and extract userId
  RoleAuthenticationFilter->>RedisStorage: load cached roles or session data
  RoleAuthenticationFilter->>JwtAuthenticationUtil: getUserRoles(userId)
  RoleAuthenticationFilter->>SecurityContextHolder: set Authentication
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • PSMRI/TM-API#56: Updates the JWT utilities and validation filter that are used by the new role-authentication flow.
  • PSMRI/TM-API#104: Overlaps with the Spring Security rollout across controller authorization and filter-chain wiring.

Suggested reviewers

  • drtechie
  • sandipkarmakar3
  • ravishanigarapu
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main purpose: releasing version 3.6.2.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch release-3.6.2

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.44.0)
src/main/java/com/iemr/tm/service/common/transaction/CommonNurseServiceImpl.java

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
14.0% Duplication on New Code (required ≤ 3%)
D Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

csrfTokenRepository.setCookieHttpOnly(true);
csrfTokenRepository.setCookiePath("/");
http
.csrf(csrf -> csrf.disable())

}
JSONObject obj = new JSONObject(comingRequest);
logger.info("getUserVanSpDetails request {}", comingRequest);

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java (1)

289-321: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Keep registrar access on the new beneficiary detail/image endpoints.

The legacy equivalents include REGISTRAR, but the new left-panel and image endpoints omit it, which can block registrar users after switching to the new flow.

🔐 Proposed fix
-	`@PreAuthorize`("hasRole('NURSE') || hasRole('DOCTOR') || hasRole('LABTECHNICIAN') || hasRole('LAB_TECHNICIAN') || hasRole('PHARMACIST')")
+	`@PreAuthorize`("hasRole('NURSE') || hasRole('DOCTOR') || hasRole('LABTECHNICIAN') || hasRole('LAB_TECHNICIAN') || hasRole('PHARMACIST') || hasRole('REGISTRAR')")
 	public String getBenDetailsForLeftSidePanelByRegID(
-	`@PreAuthorize`("hasRole('NURSE') || hasRole('DOCTOR') || hasRole('LABTECHNICIAN') || hasRole('LAB_TECHNICIAN')  || hasRole('PHARMACIST')")
+	`@PreAuthorize`("hasRole('NURSE') || hasRole('DOCTOR') || hasRole('LABTECHNICIAN') || hasRole('LAB_TECHNICIAN') || hasRole('PHARMACIST') || hasRole('REGISTRAR')")
 	public String getBenImage(`@RequestBody` String requestObj,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java`
around lines 289 - 321, The new beneficiary detail/image endpoints in
RegistrarController are missing REGISTRAR access compared with the legacy flow.
Update the `@PreAuthorize` rules on getBenDetailsForLeftSidePanelByRegID and the
new getBenImage endpoint to include REGISTRAR alongside the existing roles so
registrar users are not blocked after the switch.
src/main/java/com/iemr/tm/service/labtechnician/LabTechnicianServiceImpl.java (1)

421-460: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Persist and validate abnormalFindings at the procedure level.

Right now the new ECG field is copied onto each component row, but those rows are only materialized when a component has a result value or stripsNotAvailable=true. That means an ECG submission carrying only abnormalFindings is silently dropped, and non-ECG submissions can also populate this column because the assignment is unconditional. Please validate the procedure type and persist this field independently of the component-value gate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/service/labtechnician/LabTechnicianServiceImpl.java`
around lines 421 - 460, The handling in LabTechnicianServiceImpl’s lab result
assembly currently copies abnormalFindings onto every LabResultEntry and still
only adds rows when a component has testResultValue or stripsNotAvailable, so
ECG-only submissions can be dropped and non-ECG procedures can accidentally
carry this field. Update the loop that builds labCompResult to validate the
procedure type before setting abnormalFindings, and make sure procedure-level
abnormalFindings is persisted independently of the component-value condition
rather than being tied to the component gate.
🟠 Major comments (28)
src/main/java/com/iemr/tm/controller/foetalmonitor/FoetalMonitorController.java-31-31 (1)

31-31: 🔒 Security & Privacy | 🟠 Major

Add @PreAuthorize annotations to all endpoints; the import is unused.

The @PreAuthorize import on line 31 is not used anywhere in the controller. None of the handler methods include @PreAuthorize checks, leaving these endpoints vulnerable to access by any authenticated user rather than restricting them to the required clinical role.

Exposed Methods
`@Operation`(...)
`@PostMapping`(...) // Missing `@PreAuthorize`
public ResponseEntity<String> sendANCMotherTestDetailsToFoetalMonitor(...) {}

`@Operation`(...)
`@PostMapping`(...) // Missing `@PreAuthorize`
public String saveMother(...) {}

// ... and other exposed methods
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/controller/foetalmonitor/FoetalMonitorController.java`
at line 31, The imported `@PreAuthorize` in FoetalMonitorController is unused
because none of the controller handler methods have authorization checks. Add
the appropriate `@PreAuthorize` annotations to each exposed endpoint method in
FoetalMonitorController with the required clinical role expression, and keep the
import only if it is actually used; otherwise remove it.
src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java-18-19 (1)

18-19: 🔒 Security & Privacy | 🟠 Major

Add a check for soft-deleted mappings in the role lookup query

The query at src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java:18 currently retrieves roles without filtering out deleted entries from m_userservicerolemapping. Other native queries touching this table (e.g., in V_getVanLocDetailsRepo) explicitly verify Deleted = false. Update the subquery to include and Deleted = false to prevent stale mappings from granting access.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java` around lines 18 -
19, The role lookup in UserLoginRepo.getRoleNamebyUserId currently reads
mappings from m_userservicerolemapping without excluding soft-deleted rows.
Update the native query so the subquery filters the mapping table with Deleted =
false, matching the pattern used by other repos like V_getVanLocDetailsRepo.
Keep the change scoped to the getRoleNamebyUserId query and ensure only active
role mappings are considered.
src/main/java/com/iemr/tm/controller/common/main/WorklistController.java-710-712 (1)

710-712: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Add specialist role checks to TC specialist worklists.

These endpoints only require an authenticated principal, unlike the other specialist routes. Add @PreAuthorize so any authenticated non-specialist role cannot access TC specialist worklist data.

Proposed fix
 	`@Operation`(summary = "Get teleconsultation specialist worklist")
+	`@PreAuthorize`("hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST')")
 	`@GetMapping`(value = { "/getTCSpecialistWorklist/{providerServiceMapID}/{serviceID}" })
...
 	`@Operation`(summary = "Get teleconsultation specialist worklist for patient app")
+	`@PreAuthorize`("hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST')")
 	`@GetMapping`(value = {
 			"/getTCSpecialistWorklistPatientApp/{providerServiceMapID}/{serviceID}/{vanID}" })
...
 	`@Operation`(summary = "Get teleconsultation specialist future scheduled")
+	`@PreAuthorize`("hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST')")
 	`@GetMapping`(value = {
 			"/getTCSpecialistWorklistFutureScheduled/{providerServiceMapID}/{serviceID}" })

Also applies to: 744-747, 776-779

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/common/main/WorklistController.java`
around lines 710 - 712, Add role-based access control to the TC specialist
worklist endpoints so they are not reachable by any authenticated user; update
the specialist route handlers such as getTCSpecialistWorkListNew and the other
TC worklist methods in WorklistController to include the same `@PreAuthorize`
check used by the other specialist routes, ensuring only specialist roles can
access these endpoints.
src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java-59-75 (1)

59-75: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Apply the principal/userID binding to all from-user video actions.

The new check prevents logging in as another userID, but the same controller still exposes call actions that take fromuserID from the path. Add the same authenticated-principal check there too, or authenticated users can initiate video actions as another user.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java`
around lines 59 - 75, The principal-to-userID authorization check added in
VideoConsultationController.login must also be applied to the other from-user
video action handlers in this controller. Locate the endpoints that accept
fromuserID and Authentication, and verify the authenticated principal matches
the path user ID before calling videoConsultationService methods; otherwise
return the same unauthorized response path used in login. Keep the check
consistent across all from-user actions so authenticated users cannot initiate
video operations as another user.
src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java-73-81 (1)

73-81: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Do not log authentication tokens.

Lines 74 and 81 log the full legacy auth token, which can leak reusable credentials through application logs. Log only token presence or a non-reversible fingerprint.

Proposed fix
-                logger.info("Resolved authToken: {}", authToken);
+                logger.debug("Legacy auth token present: {}", authToken != null && !authToken.isBlank());
...
-                        logger.warn("No Redis session found for authToken: {}", authToken);
+                        logger.warn("No Redis session found for supplied legacy auth token");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java` around
lines 73 - 81, The RoleAuthenticationFilter currently logs the full legacy auth
token in both the resolveAuthToken and Redis warning paths, which can expose
reusable credentials. Update the logging around resolveAuthToken(request) and
redisService.getObject(...) to avoid printing the raw token; instead log only
that a token was present or use a non-reversible fingerprint. Keep the rest of
the authentication flow unchanged and make sure any logger.info/logger.warn
calls in this block no longer include authToken directly.
src/main/java/com/iemr/tm/utils/JwtUtil.java-62-68 (1)

62-68: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Keep public claim extraction aligned with token validation.

Line 62 now exposes a parser path that bypasses the denylist check in validateToken, so revoked JWTs can still yield claims if callers use this public method. Delegate to validateToken or keep the raw parser private.

Proposed fix
 	public Claims extractAllClaims(String token) {
-		return Jwts.parser()
-			.verifyWith(getSigningKey())
-			.build()
-			.parseSignedClaims(token)
-			.getPayload();
+		return validateToken(token);
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/JwtUtil.java` around lines 62 - 68, The
public claim extraction path in JwtUtil.extractAllClaims currently bypasses the
denylist logic enforced by validateToken, so revoked tokens can still be parsed
for claims. Update extractAllClaims to reuse validateToken (or otherwise perform
the denylist check before parsing) and keep any raw parsing helper private so
only validated JWTs can expose Claims.
src/main/java/com/iemr/tm/utils/redis/RedisStorage.java-102-107 (1)

102-107: 🔒 Security & Privacy | 🟠 Major

Ensure atomic persistence of role cache and TTL

The current cacheUserRoles method executes delete, rightPushAll, and expire as separate, non-atomic operations. If rightPushAll succeeds but expire fails (e.g., due to a transient network issue), the cached roles persist indefinitely, potentially serving stale authorization data.

Wrap these operations in a transaction or pipeline to ensure the key and its expiration are updated together.

public void cacheUserRoles(Long userId, List<String> roles) {
    try {
        String key = "roles:" + userId;
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            connection.del(key.getBytes());
            connection.rPush(key.getBytes(), roles.toArray());
            connection.expire(key.getBytes(), 1800); // 30 minutes
            return null;
        });
    } catch (Exception e) {
        logger.warn("Failed to cache role for user {} : {} ", userId, e.getMessage());
    }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/redis/RedisStorage.java` around lines 102 -
107, The cacheUserRoles method in RedisStorage currently performs delete,
rightPushAll, and expire as separate Redis calls, so the role list can be
written without a TTL if expire fails. Update this method to use a single atomic
Redis pipeline or transaction (for example via redisTemplate.executePipelined or
a transaction-based callback) so the key removal, list write, and 30-minute
expiration are applied together. Keep the existing cacheUserRoles symbol and
preserve the current error handling/logging path.
src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java-154-161 (1)

154-161: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Reject global wildcard origins when credentials are enabled.

With lines 105-107 echoing the request origin and setting Access-Control-Allow-Credentials: true, a configured * becomes credentialed CORS for any origin after this replace("*", ".*"). Treat * as invalid here and apply the same guard to the duplicate JwtUserIdValidationFilter helper.

🛡️ Proposed fix
 		return Arrays.stream(allowedOrigins.split(","))
 				.map(String::trim)
+				.filter(pattern -> !pattern.isEmpty() && !"*".equals(pattern))
 				.anyMatch(pattern -> {
 					String regex = pattern
 							.replace(".", "\\.")
 							.replace("*", ".*")
 						    .replace("http://localhost:.*", "http://localhost:\\d+");
 					return origin.matches(regex);
 				});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java` around
lines 154 - 161, The CORS origin matching in HTTPRequestInterceptor currently
turns a configured "*" into a regex that matches any origin while credentials
are enabled, so update the allowedOrigins handling to explicitly reject or
ignore "*" before building the match pattern and keep only specific origins.
Apply the same validation in the duplicate helper used by
JwtUserIdValidationFilter so both paths behave consistently, and make sure the
origin echo plus Access-Control-Allow-Credentials logic can never combine with a
wildcard config.
src/main/java/com/iemr/tm/controller/location/LocationController.java-45-45 (1)

45-45: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Allow ASHA to read location masters used during registration.

/registrar/registrarBeneficaryRegistrationNew permits ASHA, but this controller’s beneficiary location master endpoints omit that role, so ASHA users can be blocked before submitting registration.

🔐 Proposed fix
-@PreAuthorize("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST')")
+@PreAuthorize("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST') || hasRole('ASHA')")
 public class LocationController {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/location/LocationController.java` at
line 45, The LocationController security restriction is missing ASHA access,
which can block ASHA users from reading the location master data needed during
registration. Update the `@PreAuthorize` expression on the LocationController
endpoint(s) to include ASHA alongside the existing roles, matching the
registration flow permissions. Keep the change localized to the location master
access checks so ASHA can load the beneficiary location data without affecting
other authorization logic.
src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java-21-21 (1)

21-21: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Serialize the auth error instead of concatenating exception text.

authException.getMessage() is written directly into JSON, which can break the response format and expose internal auth failure details. Return a fixed client message through Jackson, matching the access-denied handler.

🛡️ Proposed fix
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 `@Component`
 public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
+    private static final ObjectMapper mapper = new ObjectMapper();
 
     `@Override`
     public void commence(HttpServletRequest request,
                          HttpServletResponse response,
                          AuthenticationException authException) throws IOException {
         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401
         response.setContentType("application/json");
-        response.getWriter().write("{\"error\": \"Unauthorized\", \"message\": \"" + authException.getMessage() + "\"}");
+        response.getWriter().write(mapper.writeValueAsString(
+                Map.of("error", "Unauthorized", "message", "Authentication required")));
     }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java`
at line 21, In CustomAuthenticationEntryPoint, stop building the unauthorized
response JSON by concatenating authException.getMessage() into the string. Use
the same Jackson-based serialization approach as the access-denied handler so
the response always returns a fixed client-facing message and cannot be broken
by exception text. Locate the change in the entry point’s write/commence logic
and replace the manual JSON write with an object serialized by the existing
ObjectMapper pattern.

Source: Linters/SAST tools

src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java-542-545 (1)

542-545: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Restrict oncologist diagnosis updates to the oncologist role.

This endpoint updates oncologist-specific diagnosis data, but Line 544 also grants NURSE and DOCTOR write access. Unless that is intentional, narrow this to ONCOLOGIST.

Suggested fix
-	`@PreAuthorize`("hasRole('NURSE') || hasRole('DOCTOR') || hasRole('ONCOLOGIST') ")
+	`@PreAuthorize`("hasRole('ONCOLOGIST')")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java`
around lines 542 - 545, The updateCancerDiagnosisDetailsByOncologist endpoint is
currently too permissive because its `@PreAuthorize` expression allows NURSE and
DOCTOR roles to perform an oncologist-specific update; tighten the authorization
on this method so only ONCOLOGIST can access it, and keep the change localized
to updateCancerDiagnosisDetailsByOncologist in CancerScreeningController.
src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java-45-75 (1)

45-75: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Short-circuit successful CORS preflights before JWT validation.

Allowed OPTIONS requests set CORS headers, then continue into JWT validation; protected endpoints will return 401 before the browser can send the real request. Return immediately after setting CORS headers for OPTIONS.

Suggested fix
 		if (origin != null && isOriginAllowed(origin)) {
 			response.setHeader("Access-Control-Allow-Origin", origin); // Never use wildcard
 			response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
 			response.setHeader("Access-Control-Allow-Headers",
 					"Authorization, Content-Type, Accept, Jwttoken, serverAuthorization, ServerAuthorization, serverauthorization, Serverauthorization");
 			response.setHeader("Access-Control-Allow-Credentials", "true");
 			response.setHeader("Access-Control-Max-Age", "3600");
 			logger.info("Origin Validated | Origin: {} | Method: {} | URI: {}", origin, method, uri);
+			if ("OPTIONS".equalsIgnoreCase(method)) {
+				response.setStatus(HttpServletResponse.SC_OK);
+				return;
+			}
 		} else {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java` around lines
45 - 75, In JwtUserIdValidationFilter, allowed CORS preflight handling for
OPTIONS requests currently continues into the JWT checks, which can trigger a
401 before the browser sends the actual request. Update the filter so that after
setting the CORS headers for a valid OPTIONS request, it exits immediately and
does not reach the JWT validation path. Keep the origin validation logic in the
same filter flow, and use the existing JwtUserIdValidationFilter method and the
OPTIONS branch to place the early return.
src/main/java/com/iemr/tm/service/health/HealthService.java-92-97 (1)

92-97: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Bound the client calls, not just the Future wait.

mysqlFuture.get(...) / redisFuture.get(...) only stop waiting in the request thread. dataSource.getConnection() and redisTemplate.execute(...) can keep blocking after cancel(true), and Executors.newFixedThreadPool(6) adds an unbounded queue behind them. During a DB/Redis outage, /health requests can pile up stuck tasks until the executor is saturated and every subsequent probe starts timing out.

Also applies to: 123-125, 140-149, 194-230

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/health/HealthService.java` around lines 92
- 97, The health checks in HealthService are only timing out the caller via
Future.get(), but the underlying dataSource.getConnection() and
redisTemplate.execute() calls can keep blocking and pile up on the fixed thread
pool. Refactor the MySQL/Redis probe methods (the ones wrapped by mysqlFuture
and redisFuture) so the client operations themselves are bounded with real
timeouts or non-blocking timeout-aware APIs, and replace the unbounded executor
setup in the HealthService constructor with a bounded execution strategy so
stuck probes cannot accumulate during outages.
src/main/java/com/iemr/tm/service/common/transaction/CommonNurseServiceImpl.java-2890-2891 (1)

2890-2891: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix the double-space typo in the new single-dose frequency literals.

"Single Dose Before Food" / "After Food" won't match the normal "Before Food" / "After Food" values. When that happens, getQtyForOneDay() stays 0 and calculateQtyPrescribed() writes a zero quantity for a valid prescription.

Suggested change
-			if (frequency.equalsIgnoreCase("Single Dose") || frequency.equalsIgnoreCase("Stat Dose")||
-					frequency.equalsIgnoreCase("Single Dose Before  Food") || frequency.equalsIgnoreCase("Single Dose After  Food")) {
+			if (frequency.equalsIgnoreCase("Single Dose") || frequency.equalsIgnoreCase("Stat Dose")||
+					frequency.equalsIgnoreCase("Single Dose Before Food") || frequency.equalsIgnoreCase("Single Dose After Food")) {
...
-							if (frequency.equalsIgnoreCase("Single Dose") || frequency.equalsIgnoreCase("Stat Dose")|| 
-									frequency.equalsIgnoreCase("Single Dose Before  Food") || frequency.equalsIgnoreCase("Single Dose After  Food")) {
+							if (frequency.equalsIgnoreCase("Single Dose") || frequency.equalsIgnoreCase("Stat Dose")|| 
+									frequency.equalsIgnoreCase("Single Dose Before Food") || frequency.equalsIgnoreCase("Single Dose After Food")) {

Also applies to: 3010-3011

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/service/common/transaction/CommonNurseServiceImpl.java`
around lines 2890 - 2891, The new single-dose frequency checks in
CommonNurseServiceImpl use misspelled literals with double spaces, so they will
not match the normal “Before Food” and “After Food” values. Update the frequency
comparisons in the affected branches, including the logic around
getQtyForOneDay() and calculateQtyPrescribed(), to use the exact standard
literals so valid prescriptions are recognized and assigned the correct
quantity.
src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java-566-576 (1)

566-576: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Remove the OpenKM URL/response logs.

These info logs can capture internal endpoints and credential- or token-bearing document URLs, plus patient-linked file identifiers. That turns routine document fetches into secret/PII leakage through application logs.

Suggested change
-			logger.info("fileUUID for fileID " + obj.getInt("fileID") + " is " + fileUUID);
-			logger.info("openkmDocUrl is " + openkmDocUrl);
+			logger.debug("Fetching OpenKM document URL for fileID={}", obj.getInt("fileID"));
...
-				logger.info("Response=" + response.getBody());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java`
around lines 566 - 576, The logging in CommonServiceImpl around the OpenKM fetch
flow is leaking sensitive data; remove the info logs that print openkmDocUrl and
the response body, and keep only non-sensitive operational logging around the
file retrieval path in the block that builds the request with
RestTemplateUtil.createRequestEntity and calls restTemplate.exchange.
src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java-578-595 (1)

578-595: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Keep the old raw-body fallback for non-JSON OpenKM responses.

new JSONObject(responseBody) now throws for plain-text/HTML error bodies, so this path 500s instead of returning the original body. That makes the integration less tolerant than before.

Suggested change
 				String responseBody = response.getBody();
 				if (responseBody != null) {
-					JSONObject responseObj = new JSONObject(responseBody);
-					if (responseObj.has("data")) {
-						Object dataVal = responseObj.get("data");
-						if (dataVal instanceof JSONObject) {
-							JSONObject dataObj = (JSONObject) dataVal;
-							if (dataObj.has("response")) {
-								String fileUrl = dataObj.getString("response");
-								// Fix malformed URL: https://user:pass@https://host -> https://user:pass@host
-								fileUrl = fileUrl.replaceAll("`@https`?://", "@");
-								return fileUrl;
-							}
-						}
-						return dataVal.toString();
-					}
+					try {
+						JSONObject responseObj = new JSONObject(responseBody);
+						if (responseObj.has("data")) {
+							Object dataVal = responseObj.get("data");
+							if (dataVal instanceof JSONObject) {
+								JSONObject dataObj = (JSONObject) dataVal;
+								if (dataObj.has("response")) {
+									String fileUrl = dataObj.getString("response");
+									fileUrl = fileUrl.replaceAll("`@https`?://", "@");
+									return fileUrl;
+								}
+							}
+							return dataVal.toString();
+						}
+					} catch (JSONException ex) {
+						return responseBody;
+					}
 				}
 				return responseBody;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java`
around lines 578 - 595, The response parsing in CommonServiceImpl should
preserve the old raw-body fallback for non-JSON OpenKM responses. Update the
logic around responseBody parsing so JSONObject construction is only attempted
when the body is actually JSON, and if parsing fails or the payload is plain
text/HTML, return the original responseBody instead of throwing. Keep the
existing data/response extraction path and URL fix, but make sure the fallback
behavior in this method remains tolerant for malformed or non-JSON bodies.
src/main/java/com/iemr/tm/utils/StringListConverter.java-39-50 (1)

39-50: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve empty lists instead of collapsing them to null.

This converter is lossy today: an empty list is stored as NULL and read back as null. That breaks round-tripping and makes “unset” indistinguishable from “explicitly empty”.

Suggested change
+import java.util.Collections;
...
     `@Override`
     public String convertToDatabaseColumn(List<String> attribute) {
-        if (attribute == null || attribute.isEmpty()) {
+        if (attribute == null) {
             return null;
         }
         return gson.toJson(attribute);
     }

     `@Override`
     public List<String> convertToEntityAttribute(String dbData) {
-        if (dbData == null || dbData.trim().isEmpty()) {
+        if (dbData == null) {
             return null;
         }
-        return gson.fromJson(dbData, new TypeToken<List<String>>(){}.getType());
+        if (dbData.trim().isEmpty()) {
+            return Collections.emptyList();
+        }
+        List<String> values = gson.fromJson(dbData, new TypeToken<List<String>>(){}.getType());
+        return values != null ? values : Collections.emptyList();
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/StringListConverter.java` around lines 39 -
50, The StringListConverter is collapsing empty lists into null, which breaks
round-tripping between entity and database values. Update
convertToDatabaseColumn in StringListConverter so that an empty List<String> is
serialized instead of returning null, while still handling a null attribute
separately. Keep convertToEntityAttribute aligned with this behavior so an empty
persisted value restores to an empty list rather than null, preserving the
distinction between unset and explicitly empty.
src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java-42-44 (1)

42-44: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Scope the lab-tech role to the new endpoint only.

Making LABTECHNICIAN/LAB_TECHNICIAN a class-level allowance also opens the existing nurse/doctor master-data endpoints to that role. If the goal is only to expose /master/ecgAbnormalFindings, keep the broader access on that method instead of the whole controller.

Suggested access split
-@PreAuthorize("hasRole('NURSE') || hasRole('DOCTOR') || hasRole('LABTECHNICIAN') || hasRole('LAB_TECHNICIAN')")
+@PreAuthorize("hasRole('NURSE') || hasRole('DOCTOR')")
 public class CommonMasterController {
+	`@PreAuthorize`("hasRole('NURSE') || hasRole('DOCTOR') || hasRole('LABTECHNICIAN') || hasRole('LAB_TECHNICIAN')")
 	`@Operation`(summary = "Get ECG abnormal findings master data")
 	`@GetMapping`(value = "/ecgAbnormalFindings", produces = MediaType.APPLICATION_JSON)
 	public String getECGAbnormalFindings() {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java`
around lines 42 - 44, The class-level access on CommonMasterController currently
grants LABTECHNICIAN/LAB_TECHNICIAN to every master-data endpoint, which
unintentionally broadens access beyond the new ECG route. Move the lab-tech
roles off the controller-level `@PreAuthorize` and apply them only to the
ECG-specific handler (the method for /master/ecgAbnormalFindings), while keeping
the existing nurse/doctor restrictions on the rest of the controller. Use the
controller class annotation and the ECG endpoint method name to locate the split
and preserve the broader access only where intended.
src/main/java/com/iemr/tm/service/anc/ANCServiceImpl.java-1496-1500 (1)

1496-1500: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Do not treat an omitted signature flag as false on update.

For update flows, defaulting an absent doctorSignatureFlag to false can overwrite an existing saved signature. Preserve the current value when the field is omitted; use explicit false only when the client sends it.

Also applies to: 1608-1609

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/anc/ANCServiceImpl.java` around lines 1496
- 1500, The update handling in ANCServiceImpl is defaulting doctorSignatureFlag
to false when the field is omitted, which can overwrite an existing saved
signature; adjust the requestOBJ parsing in the update flow so omitted
doctorSignatureFlag values preserve the current stored value, and only set false
when the client explicitly sends false. Apply the same fix to the other
doctorSignatureFlag handling near the related update logic so the behavior is
consistent.
src/main/java/com/iemr/tm/service/covid19/Covid19ServiceImpl.java-1195-1198 (1)

1195-1198: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve existing signature state when the update payload omits the flag.

Defaulting doctorSignatureFlag to false makes older/partial update clients clear a previously stored signature. Pass a nullable “not provided” value or otherwise preserve the existing DB value unless the client explicitly sends false.

Also applies to: 1317-1318

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/covid19/Covid19ServiceImpl.java` around
lines 1195 - 1198, The update flow in Covid19ServiceImpl is overwriting an
existing doctor signature state by defaulting doctorSignatureFlag to false when
the payload omits it. Change the handling in the update logic so the flag stays
nullable or otherwise indicates “not provided,” and only apply a change when the
request explicitly includes doctorSignatureFlag; use the existing update paths
in Covid19ServiceImpl around the doctorSignatureFlag assignment sites to
preserve the stored DB value for partial updates.
src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java-1211-1214 (1)

1211-1214: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve existing signature state when the update payload omits the flag.

Missing doctorSignatureFlag currently becomes false and is propagated to the flow update, which can unintentionally reset a previously true signature flag. Preserve existing state unless the field is explicitly supplied.

Also applies to: 1324-1325

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java` around
lines 1211 - 1214, The update flow in NCDCareServiceImpl is defaulting
doctorSignatureFlag to false when the request omits it, which can overwrite an
existing true value; change the parsing logic so the flag is only updated when
requestOBJ explicitly contains doctorSignatureFlag, and otherwise preserve the
current flow state. Apply the same behavior in both the signature handling block
around doctorSignatureFlag and the later update path that also reads this field,
using the existing NCDCareServiceImpl update methods/variables to keep the prior
signature value unchanged unless provided.
src/main/java/com/iemr/tm/service/common/transaction/CommonDoctorServiceImpl.java-198-203 (1)

198-203: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make duplicate suppression atomic.

Line 199 checks for an existing observation and Line 202 inserts afterward, so concurrent saves for the same beneficiary/visit can both see null and create duplicates. Enforce this with a DB uniqueness/atomic insert strategy instead of a non-atomic pre-check.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/service/common/transaction/CommonDoctorServiceImpl.java`
around lines 198 - 203, The duplicate check in CommonDoctorServiceImpl’s
observation save flow is non-atomic, so concurrent calls can both pass
getBenClinicalObservationStatus and then save duplicates. Replace the pre-check
in this save block with an atomic database-backed guard, such as a unique
constraint on beneficiaryRegID plus visitCode and handling the insert conflict
in the getBenClinicalObservations/save path. Keep the logic centered around
CommonDoctorServiceImpl and benClinicalObservationsRepo, but rely on the
database to enforce one record per beneficiary/visit.
src/main/java/com/iemr/tm/service/generalOPD/GeneralOPDServiceImpl.java-1368-1371 (1)

1368-1371: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve existing signature state when the update payload omits the flag.

This update path treats absence as false, so an update request that does not include doctorSignatureFlag can clear an existing signed state. Keep absence distinct from explicit false.

Also applies to: 1486-1487

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/generalOPD/GeneralOPDServiceImpl.java`
around lines 1368 - 1371, The update logic in GeneralOPDServiceImpl currently
defaults doctorSignatureFlag to false when the field is missing, which can
unintentionally clear an existing signed state. In the update paths around the
doctorSignatureFlag handling (including the later occurrence noted in the same
service), distinguish “missing” from explicit false by only changing the stored
signature state when the payload actually contains doctorSignatureFlag, and
otherwise leave the current value unchanged. Use the existing
doctorSignatureFlag variable and the requestOBJ JSON checks to gate the
assignment rather than applying a default false.
src/main/java/com/iemr/tm/service/pnc/PNCServiceImpl.java-1389-1392 (1)

1389-1392: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve existing signature state when the update payload omits the flag.

An omitted doctorSignatureFlag is currently indistinguishable from an explicit false, so partial update requests can clear an existing signature. Use nullable/preserve semantics for update paths.

Also applies to: 1501-1502

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/pnc/PNCServiceImpl.java` around lines 1389
- 1392, The update path in PNCServiceImpl is treating a missing
doctorSignatureFlag the same as false, which can clear an existing signature
during partial updates. Adjust the logic around the doctorSignatureFlag handling
in the relevant update methods so omitted values are represented as null or
otherwise preserved, and only apply a boolean change when the field is actually
present in the request payload. Use the existing doctorSignatureFlag variable
and the related update flow near the repeated assignment sites to keep the
current signature state intact when the flag is absent.
src/main/java/com/iemr/tm/service/quickConsultation/QuickConsultationServiceImpl.java-529-532 (1)

529-532: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve existing signature state when the update payload omits the flag.

The update path defaults absence to false and then persists it through the flow update. That can reset an existing signed state for clients that do not send the new field.

Also applies to: 620-621

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/service/quickConsultation/QuickConsultationServiceImpl.java`
around lines 529 - 532, The update flow in QuickConsultationServiceImpl is
resetting doctorSignatureFlag to false when the request omits it, which can
overwrite an existing signed state. Change the handling around
quickConsultDoctorOBJ so the flag is only updated when the payload explicitly
includes doctorSignatureFlag, and otherwise preserve the current persisted value
through the flow update. Apply the same fix in both the signature extraction and
downstream update/persistence logic that uses doctorSignatureFlag.
src/main/java/com/iemr/tm/service/common/transaction/CommonDoctorServiceImpl.java-685-689 (1)

685-689: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Avoid inserting a second referral row after updating existing rows.

Lines 640-652 already update existing referral rows; this fallback then saves a fresh referDetails when no additional-service list is present, causing duplicate referral rows on update. Only add the fallback row when there were no existing statuses to update.

Proposed fix
-		} else {
+		} else if (benReferDetailsStatuses == null || benReferDetailsStatuses.isEmpty()) {
 			if (referDetails.getReferredToInstituteName() != null ||
 					referDetails.getRevisitDate() != null || referDetails.getReferralReason() != null) {
 				referDetailsList.add(referDetails);
 			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/iemr/tm/service/common/transaction/CommonDoctorServiceImpl.java`
around lines 685 - 689, The fallback in CommonDoctorServiceImpl should not add a
new referDetails row when the earlier referral-status update path has already
found existing rows to update. In the method handling referral persistence,
guard the else branch so referDetailsList only gets a fresh entry when there
were no existing statuses/records updated (and the additional-service list is
absent), using the existing referral update flow and referDetailsList as the key
points to adjust.
src/main/java/com/iemr/tm/service/anc/ANCServiceImpl.java-353-356 (1)

353-356: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Move signature parsing inside the existing null guard.

Line 354 dereferences requestOBJ before Line 358 checks it, so a null input now throws immediately instead of following the existing null-handling path.

Proposed fix
-		Boolean doctorSignatureFlag = false;
-		if (requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
-			doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
-		}
-
 		if (requestOBJ != null) {
+			Boolean doctorSignatureFlag = false;
+			if (requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
+				doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
+			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/anc/ANCServiceImpl.java` around lines 353 -
356, Move the doctor signature parsing in ANCServiceImpl into the existing
request null-handling path so requestOBJ is never dereferenced before the null
check; update the logic around doctorSignatureFlag to first verify requestOBJ is
non-null, then read the doctorSignatureFlag field only within that guard,
preserving the existing fallback behavior when the request is null.
src/main/java/com/iemr/tm/service/cancerScreening/CSServiceImpl.java-814-820 (1)

814-820: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Move doctorSignatureFlag parsing behind the null guard.

Line 815 dereferences requestOBJ before Line 820 checks it for null, so a null request now fails with an NPE instead of the existing invalid-input path.

Proposed fix
-		Boolean doctorSignatureFlag = false;
-			if (requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
-			doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
-			}
-
-
-
 		if (requestOBJ != null && requestOBJ.has("diagnosis") && !requestOBJ.get("diagnosis").isJsonNull()) {
+			Boolean doctorSignatureFlag = false;
+			if (requestOBJ.has("doctorSignatureFlag") && !requestOBJ.get("doctorSignatureFlag").isJsonNull()) {
+				doctorSignatureFlag = requestOBJ.get("doctorSignatureFlag").getAsBoolean();
+			}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/service/cancerScreening/CSServiceImpl.java` around
lines 814 - 820, The doctorSignatureFlag parsing in CSServiceImpl should be
moved behind the existing requestOBJ null guard because it currently
dereferences requestOBJ before the null check. Update the request handling logic
so the doctorSignatureFlag extraction happens only after confirming requestOBJ
is non-null, using the same pattern already applied to the diagnosis parsing
block, to preserve the invalid-input path and avoid an NPE.
🟡 Minor comments (3)
src/main/java/com/iemr/tm/controller/common/main/WorklistController.java-1031-1031 (1)

1031-1031: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include the TCSPECIALIST alias for session extension.

Other TC specialist endpoints accept both TC_SPECIALIST and TCSPECIALIST, but this role list only includes TC_SPECIALIST. Users with the alias can be denied session extension.

Proposed fix
-	`@PreAuthorize`("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST')")
+	`@PreAuthorize`("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST')")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/common/main/WorklistController.java` at
line 1031, The session extension role check in WorklistController is missing the
TCSPECIALIST alias, so users with that alias can be blocked even though other TC
specialist endpoints allow it. Update the `@PreAuthorize` expression on the
session extension endpoint to include both TC_SPECIALIST and TCSPECIALIST,
matching the existing role-alias pattern used elsewhere in the controller.
src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java-49-49 (1)

49-49: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep TC specialist role aliases consistent.

Line 49 allows TC_SPECIALIST but not TCSPECIALIST, while other controller methods support both aliases. Add the missing alias to avoid denying valid TC specialist users.

Proposed fix
-@PreAuthorize("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST') || hasRole('ASHA')")
+@PreAuthorize("hasRole('NURSE') || hasRole('PHARMACIST') || hasRole('LABTECHNICIAN') || hasRole('REGISTRAR') || hasRole('DATASYNC') || hasRole('DATA_SYNC') || hasRole('DOCTOR') || hasRole('LAB_TECHNICIAN') || hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST') || hasRole('ONCOLOGIST') || hasRole('RADIOLOGIST') || hasRole('ASHA')")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java` at
line 49, The role check in IemrMmuLoginController is missing the TC specialist
alias used elsewhere, so valid users with that role can be denied access. Update
the `@PreAuthorize` expression on the login controller method to include both
TC_SPECIALIST and TCSPECIALIST, matching the alias handling already used in the
other controller methods and keeping the role names consistent.
src/main/java/com/iemr/tm/repo/labModule/ECGAbnormalFindingMasterRepo.java-31-34 (1)

31-34: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Return the master list in a deterministic order.

findByDeleted(Boolean deleted) leaves row order up to the database, so the ECG findings list can reshuffle between calls. Prefer an ordered query such as findByDeletedFalseOrderByFindingNameAsc() (or by FindingID if that is the canonical sequence).

Suggested repository signature
-public interface ECGAbnormalFindingMasterRepo extends CrudRepository<ECGAbnormalFindingMaster, Integer> {
-
-	List<ECGAbnormalFindingMaster> findByDeleted(Boolean deleted);
+public interface ECGAbnormalFindingMasterRepo extends CrudRepository<ECGAbnormalFindingMaster, Integer> {
+
+	List<ECGAbnormalFindingMaster> findByDeletedFalseOrderByFindingNameAsc();
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/repo/labModule/ECGAbnormalFindingMasterRepo.java`
around lines 31 - 34, The ECG abnormal findings repository currently returns
rows in an undefined order, which can cause the master list to reshuffle between
calls. Update ECGAbnormalFindingMasterRepo by replacing or supplementing
findByDeleted(Boolean deleted) with an ordered derived query such as
findByDeletedFalseOrderByFindingNameAsc() (or by FindingID if that is the
canonical sort), so callers always receive a deterministic list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fac3adae-e57e-4436-84c0-9aae64a676c5

📥 Commits

Reviewing files that changed from the base of the PR and between 2c8fdd2 and 799a627.

📒 Files selected for processing (67)
  • pom.xml
  • src/main/environment/common_ci.properties
  • src/main/environment/common_docker.properties
  • src/main/environment/common_example.properties
  • src/main/java/com/iemr/tm/controller/anc/AntenatalCareController.java
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java
  • src/main/java/com/iemr/tm/controller/common/main/WorklistController.java
  • src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java
  • src/main/java/com/iemr/tm/controller/covid19/CovidController.java
  • src/main/java/com/iemr/tm/controller/dataSyncActivity/StartSyncActivity.java
  • src/main/java/com/iemr/tm/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java
  • src/main/java/com/iemr/tm/controller/foetalmonitor/FoetalMonitorController.java
  • src/main/java/com/iemr/tm/controller/generalOPD/GeneralOPDController.java
  • src/main/java/com/iemr/tm/controller/health/HealthController.java
  • src/main/java/com/iemr/tm/controller/labtechnician/LabtechnicianController.java
  • src/main/java/com/iemr/tm/controller/location/LocationController.java
  • src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java
  • src/main/java/com/iemr/tm/controller/ncdCare/NCDCareController.java
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java
  • src/main/java/com/iemr/tm/controller/nurse/vitals/AnthropometryVitalsController.java
  • src/main/java/com/iemr/tm/controller/patientApp/master/PatientAppCommonMasterController.java
  • src/main/java/com/iemr/tm/controller/pnc/PostnatalCareController.java
  • src/main/java/com/iemr/tm/controller/quickconsult/QuickConsultController.java
  • src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java
  • src/main/java/com/iemr/tm/controller/report/CRMReportController.java
  • src/main/java/com/iemr/tm/controller/snomedct/SnomedController.java
  • src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java
  • src/main/java/com/iemr/tm/controller/version/VersionController.java
  • src/main/java/com/iemr/tm/controller/videoconsultationcontroller/VideoConsultationController.java
  • src/main/java/com/iemr/tm/data/benFlowStatus/BeneficiaryFlowStatus.java
  • src/main/java/com/iemr/tm/data/labModule/ECGAbnormalFindingMaster.java
  • src/main/java/com/iemr/tm/data/labModule/LabResultEntry.java
  • src/main/java/com/iemr/tm/data/ncdcare/NCDCareDiagnosis.java
  • src/main/java/com/iemr/tm/repo/benFlowStatus/BeneficiaryFlowStatusRepo.java
  • src/main/java/com/iemr/tm/repo/labModule/ECGAbnormalFindingMasterRepo.java
  • src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java
  • src/main/java/com/iemr/tm/repo/nurse/ncdcare/NCDCareDiagnosisRepo.java
  • src/main/java/com/iemr/tm/repo/quickConsultation/BenClinicalObservationsRepo.java
  • src/main/java/com/iemr/tm/service/anc/ANCServiceImpl.java
  • src/main/java/com/iemr/tm/service/benFlowStatus/CommonBenStatusFlowServiceImpl.java
  • src/main/java/com/iemr/tm/service/cancerScreening/CSServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/master/CommonMasterServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/master/CommonMaterService.java
  • src/main/java/com/iemr/tm/service/common/transaction/CommonDoctorServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/transaction/CommonNurseServiceImpl.java
  • src/main/java/com/iemr/tm/service/common/transaction/CommonServiceImpl.java
  • src/main/java/com/iemr/tm/service/covid19/Covid19ServiceImpl.java
  • src/main/java/com/iemr/tm/service/generalOPD/GeneralOPDServiceImpl.java
  • src/main/java/com/iemr/tm/service/health/HealthService.java
  • src/main/java/com/iemr/tm/service/labtechnician/LabTechnicianServiceImpl.java
  • src/main/java/com/iemr/tm/service/ncdCare/NCDCareServiceImpl.java
  • src/main/java/com/iemr/tm/service/ncdscreening/NCDSCreeningDoctorServiceImpl.java
  • src/main/java/com/iemr/tm/service/ncdscreening/NCDScreeningServiceImpl.java
  • src/main/java/com/iemr/tm/service/pnc/PNCServiceImpl.java
  • src/main/java/com/iemr/tm/service/quickConsultation/QuickConsultationServiceImpl.java
  • src/main/java/com/iemr/tm/utils/CookieUtil.java
  • src/main/java/com/iemr/tm/utils/IntegerListConverter.java
  • src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java
  • src/main/java/com/iemr/tm/utils/JwtUserIdValidationFilter.java
  • src/main/java/com/iemr/tm/utils/JwtUtil.java
  • src/main/java/com/iemr/tm/utils/StringListConverter.java
  • src/main/java/com/iemr/tm/utils/exception/CustomAccessDeniedHandler.java
  • src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java
  • src/main/java/com/iemr/tm/utils/http/HTTPRequestInterceptor.java
  • src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java
  • src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java
  • src/main/java/com/iemr/tm/utils/redis/RedisStorage.java

Comment on lines 49 to +50
@RequestMapping(value = "/dataSyncActivity", headers = "Authorization", consumes = "application/json", produces = "application/json")
@PreAuthorize("hasRole('DATASYNC') || hasRole('DATA_SYNC') ")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for data-sync role seeds, mappings, tests, or auth-token handling around sync callers.
rg -n -C4 --iglob '*.java' --iglob '*.sql' --iglob '*.properties' --iglob '*.xml' \
  '(DATASYNC|DATA_SYNC|ServerAuthorization|dataSyncActivity|/dataSync|m_userservicerolemapping)' .

Repository: PSMRI/TM-API

Length of output: 26817


🏁 Script executed:

rg -n "ServerAuthorization" --type java -A 5 -B 5 | rg -i "filter|context|security|authentication" -A 10 -B 10

Repository: PSMRI/TM-API

Length of output: 150


🏁 Script executed:

#!/bin/bash
# Check for any SecurityFilter, Filter, or Interceptor that handles ServerAuthorization
rg -l "Filter" --type java | xargs -I {} sh -c 'echo "=== {} ==="; cat {}' | rg -C 5 "ServerAuthorization"

Repository: PSMRI/TM-API

Length of output: 150


🏁 Script executed:

#!/bin/bash
# Check for any SecurityFilter, Filter, or Interceptor that handles ServerAuthorization explicitly
rg -n "ServerAuthorization" --type java -A 10 | rg -C 10 "SecurityContext|Authentication"

Repository: PSMRI/TM-API

Length of output: 150


🏁 Script executed:

#!/bin/bash
# Search for security configuration or filters handling ServerAuthorization
rg -n "ServerAuthorization" --type java -A 5 -B 5

Repository: PSMRI/TM-API

Length of output: 150


🏁 Script executed:

#!/bin/bash
# Search for security configuration or filters handling ServerAuthorization (case-insensitive)
rg -in "serverauthorization" --type java -A 5 -B 5

Repository: PSMRI/TM-API

Length of output: 150


Verify role resolution for ServerAuthorization-based sync calls.

The @PreAuthorize check at lines 49-50 relies on the Spring Authentication derived from the Authorization (JWT) header, but the sync logic delegates to services using the ServerAuthorization header. There is no evidence of a filter or interceptor mapping ServerAuthorization credentials to the DATASYNC or DATA_SYNC security roles. This disconnect implies that valid sync requests failing to provide a JWT with these roles will be incorrectly blocked, or the check is only protecting endpoints that use JWT roles and not the ServerAuthorization mechanism. Ensure the security configuration correctly maps sync credentials to these roles or remove the role check if ServerAuthorization is the intended authority.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/controller/dataSyncActivity/StartSyncActivity.java`
around lines 49 - 50, The `StartSyncActivity` endpoint’s `@PreAuthorize` guard
is tied to Spring `Authentication` from the `Authorization` JWT, but the sync
flow uses `ServerAuthorization`, so the role check may not reflect the real auth
mechanism. Update the security setup around `StartSyncActivity` to either map
`ServerAuthorization` credentials into `DATASYNC`/`DATA_SYNC` authorities before
`@PreAuthorize` runs, or remove/replace the role check if `ServerAuthorization`
is the intended source of trust. Verify the behavior in the controller entry
point and the related security filter/interceptor configuration.

Comment on lines +35 to +39
CookieCsrfTokenRepository csrfTokenRepository = new CookieCsrfTokenRepository();
csrfTokenRepository.setCookieHttpOnly(true);
csrfTokenRepository.setCookiePath("/");
http
.csrf(csrf -> csrf.disable())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether authentication can be derived from cookies and whether CSRF config is intentionally unused.
fd -i 'CookieUtil\.java|Jwt.*Filter\.java|RoleAuthenticationFilter\.java|JwtAuthenticationUtil\.java|SecurityConfig\.java' src/main/java --exec sh -c '
  echo "### $1"
  rg -n -C2 "Cookie|cookies|getCookies|Authorization|csrf|CookieCsrfTokenRepository|setCookie|addCookie" "$1"
' sh {}

Repository: PSMRI/TM-API

Length of output: 7179


🏁 Script executed:

#!/bin/bash
# Read the full SecurityConfig.java to verify the context and line numbers.
cat -n src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java

Repository: PSMRI/TM-API

Length of output: 3098


Disable CSRF protection while using cookies for authentication creates a security vulnerability.

The code configures CookieCsrfTokenRepository (lines 35-37) but immediately disables CSRF globally at line 39. Since CookieUtil and JwtUserIdValidationFilter extract the Jwttoken from cookies for authentication, disabling CSRF exposes the application to cross-site request forgery attacks on all authenticated state-changing endpoints.

  1. Remove Dead Code: The CookieCsrfTokenRepository configuration is unused and should be removed.
  2. Enable CSRF: Remove .csrf(csrf -> csrf.disable()) to enforce CSRF protection for cookie-based authentication.
🧰 Tools
🪛 ast-grep (0.44.0)

[warning] 37-38: Do not disable CSRF
Context: http
.csrf(csrf -> csrf.disable())
Note: [CWE-352] Cross-Site Request Forgery (CSRF).

(spring-csrf-disable)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java` around lines 35 -
39, The SecurityConfig setup is configuring a CookieCsrfTokenRepository but then
disabling CSRF entirely, leaving cookie-based authentication exposed; update the
HttpSecurity configuration to keep CSRF protection enabled and remove the unused
CookieCsrfTokenRepository setup if it is not being applied anywhere. Make the
fix in SecurityConfig where the security filter chain is built, and ensure the
cookie-based Jwttoken flow used by CookieUtil and JwtUserIdValidationFilter
remains protected by CSRF rather than bypassed.

Source: Linters/SAST tools

.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers("/user/*").permitAll()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# List user/login controller mappings to verify what /user/* exposes publicly.
fd -i 'IemrMmuLoginController\.java|.*User.*Controller\.java|.*Login.*Controller\.java' src/main/java --exec sh -c '
  echo "### $1"
  rg -n -C3 "@(RequestMapping|GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping)|/user|password|profile|role|admin" "$1"
' sh {}

Repository: PSMRI/TM-API

Length of output: 2057


Restrict public access to /user/* endpoints internally protected by roles

The pattern .requestMatchers("/user/*").permitAll() is too broad. While the base path for IemrMmuLoginController includes a headers constraint, the route /user/* encompasses internal business logic endpoints (e.g., getUserServicePointVanDetails) that require role-based authentication (hasRole) and are not intended for public access. Relying on method-level @PreAuthorize to block anonymous traffic allowed by the URL matcher introduces a security risk.

Replace the broad wildcard with specific public endpoints or remove permitAll() for this path entirely.

Diff context
            .requestMatchers("/user/*").permitAll()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java` at line 42,
Restrict the overly broad public matcher in SecurityConfig: the current
requestMatchers("/user/*").permitAll() exposes internal user endpoints that
should be role-protected. Update the security configuration to remove this
wildcard permitAll or replace it with only the specific public routes used by
IemrMmuLoginController, and leave protected user operations to the existing
hasRole / `@PreAuthorize` controls so endpoints like getUserServicePointVanDetails
are not anonymously reachable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants