Skip to content

Conversation

@vanitha1822
Copy link
Contributor

@vanitha1822 vanitha1822 commented Nov 27, 2025

📋 Description

JIRA ID:

AMM-1921

Implement Role-based access control for the API's with the roles: Nurse, Registrar, DataSync, Doctor, LabTechnician, Pharmacist, Oncologist, Radiologist and TCSpecialist


✅ Type of Change

  • 🛠 Refactor (change that is neither a fix nor a new feature)

Summary by CodeRabbit

Release Notes

  • New Features

    • Implemented role-based access control across the application. Users now require appropriate roles (Nurse, Doctor, Registrar, Lab Technician, Pharmacist, Oncologist, etc.) to access specific features and endpoints.
    • Enhanced authentication and authorization framework with improved security enforcement and error handling.
  • Chores

    • Added Spring Security framework to support access control infrastructure.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

This PR implements Spring Security role-based access control across the application by adding security dependencies, creating authentication filters and configuration, annotating controller endpoints with @PreAuthorize decorators to enforce role restrictions, integrating JWT token handling, and implementing Redis-backed role caching.

Changes

Cohort / File(s) Change Summary
Maven Dependencies
pom.xml
Adds Spring Security starter dependency twice (duplicate entries for org.springframework.boot:spring-boot-starter-security)
Security Infrastructure Components
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/mapper/RoleAuthenticationFilter.java, src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java
Introduces new Spring Security components: CustomAccessDeniedHandler (403 response handler), CustomAuthenticationEntryPoint (401 response handler), RoleAuthenticationFilter (extracts JWT, fetches user roles from Redis or userService), and SecurityConfig (configures security filter chain with stateless session management)
Controller Role-Based Access Restrictions (Nurse/Doctor Focus)
src/main/java/com/iemr/tm/controller/anc/AntenatalCareController.java, src/main/java/com/iemr/tm/controller/covid19/CovidController.java, src/main/java/com/iemr/tm/controller/generalOPD/GeneralOPDController.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/pnc/PostnatalCareController.java, src/main/java/com/iemr/tm/controller/quickconsult/QuickConsultController.java
Adds @PreAuthorize annotations to endpoints restricting access to NURSE and/or DOCTOR roles; methods handling nurse data require NURSE role, doctor data require DOCTOR role, and retrieval/update methods allow NURSE || DOCTOR
Controller Role-Based Access Restrictions (Multi-Role)
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/location/LocationController.java, src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java, src/main/java/com/iemr/tm/controller/report/CRMReportController.java, src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java
Adds @PreAuthorize class-level or method-level annotations supporting multiple roles (DOCTOR, NURSE, LAB_TECHNICIAN, PHARMACIST, REGISTRAR, ONCOLOGIST, RADIOLOGIST, TC_SPECIALIST, DATASYNC, DATA_SYNC variants)
Controller Role-Based Access Restrictions (Single Role)
src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.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/labtechnician/LabtechnicianController.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/snomedct/SnomedController.java, src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java
Adds @PreAuthorize annotations at class level restricting access to single or paired roles (NURSE, DOCTOR, REGISTRAR, LAB_TECHNICIAN, DATASYNC, DATA_SYNC, TCSPECIALIST, TC_SPECIALIST, ONCOLOGIST, RADIOLOGIST)
JWT & Authentication Utilities
src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java, src/main/java/com/iemr/tm/utils/JwtUtil.java
Adds new public method getUserRoles(Long userId) in JwtAuthenticationUtil with validation and exception handling; exposes extractAllClaims from private to public in JwtUtil
Repository & Role Caching
src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java, src/main/java/com/iemr/tm/utils/redis/RedisStorage.java
Adds getRoleNamebyUserId(Long userID) repository query method; introduces Redis list-based methods cacheUserRoles and getUserRoleFromCache for role persistence with error logging

Sequence Diagram

sequenceDiagram
    participant Client
    participant RoleAuthFilter as RoleAuthenticationFilter
    participant JwtUtil
    participant JwtAuthUtil as JwtAuthenticationUtil
    participant UserService
    participant Redis
    participant PreAuthorize
    participant Controller
    participant CustomHandler as CustomAccessDeniedHandler/<br/>CustomAuthenticationEntryPoint

    Client->>RoleAuthFilter: Request with JWT
    RoleAuthFilter->>JwtUtil: Extract token from cookie/header
    alt Token valid
        JwtUtil-->>RoleAuthFilter: userId extracted
        RoleAuthFilter->>Redis: getUserRoleFromCache(userId)
        alt Roles cached
            Redis-->>RoleAuthFilter: Roles list
        else Cache miss
            RoleAuthFilter->>JwtAuthUtil: getUserRoles(userId)
            JwtAuthUtil->>UserService: Fetch roles
            UserService-->>JwtAuthUtil: Roles
            JwtAuthUtil-->>RoleAuthFilter: Roles
            RoleAuthFilter->>Redis: cacheUserRoles(userId, roles)
            Redis-->>RoleAuthFilter: Cached
        end
        RoleAuthFilter->>RoleAuthFilter: Set SecurityContext with GrantedAuthorities
    else Invalid/Missing token
        RoleAuthFilter->>CustomHandler: AuthenticationException
        CustomHandler-->>Client: 401 Unauthorized (JSON)
    end
    
    RoleAuthFilter->>PreAuthorize: Check `@PreAuthorize` role expression
    alt Role matches
        PreAuthorize->>Controller: Allow access
        Controller-->>Client: Response 200
    else Role denied
        PreAuthorize->>CustomHandler: AccessDeniedException
        CustomHandler-->>Client: 403 Forbidden (JSON)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Security configuration completeness: Verify SecurityConfig properly chains all filters, CSRF handling, and session management align with security requirements
  • Role annotation consistency: Review that all @PreAuthorize expressions across 20+ controllers follow consistent patterns and grant appropriate role combinations (especially NURSE || DOCTOR vs. individual roles)
  • JWT token extraction flow: Validate RoleAuthenticationFilter correctly handles edge cases (missing token, invalid format, expired claims) and doesn't introduce bypass paths
  • Redis caching strategy: Confirm getUserRoleFromCache/cacheUserRoles error handling (warnings vs. exceptions) and TTL behavior match production expectations
  • Duplicate dependency in pom.xml: Address the redundant Spring Security starter entries to avoid build/classpath conflicts
  • Method visibility change in JwtUtil: Ensure exposing extractAllClaims from private to public doesn't create unintended access patterns or security gaps

Possibly related PRs

  • jwt api implementation #56: Implements JWT-based authentication with JwtUtil, JwtAuthenticationUtil, and security filter wiring with Redis integration—directly related infrastructure changes
  • Fix the WASA Issue : IDOR Vulnerability #102: Modifies JwtUtil and adds token-based role/ID checks to controllers (e.g., TeleConsultationController)—overlapping JWT and controller-level security patterns

Suggested reviewers

  • drtechie
  • vishwab1
  • sandipkarmakar3

Poem

🐰 A Rabbit's Security Sonnet

With @PreAuthorize the roles align,
JWT tokens dance through Redis cache so fine,
Role-based gates now guard the endpoints' line,
A cottony filter makes the flow divine!

Hop-hop-hooray for auth that's crystalline! 🔐

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.65% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the primary change—implementing role-based access control (RBAC) with the WASA identifier, which aligns with the changeset's primary focus across all modified files.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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 and usage tips.

@vanitha1822
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 27, 2025

✅ Actions performed

Full review triggered.

@vanitha1822 vanitha1822 self-assigned this Nov 27, 2025
@vanitha1822 vanitha1822 requested a review from drtechie November 27, 2025 06:01
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

Caution

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

⚠️ Outside diff range comments (4)
src/main/java/com/iemr/tm/utils/JwtUtil.java (1)

62-68: Critical: Exposing extractAllClaims bypasses denylist validation.

Making this method public creates a security vulnerability. Callers can now extract claims from denylisted tokens (e.g., tokens from logged-out users), bypassing the denylist check that exists only in validateToken (lines 42-45). This undermines the authentication security being implemented in this PR.

Recommended solution: Keep the method private and ensure all claim extraction goes through validateToken. If external access is required, refactor to eliminate duplication:

-	public Claims extractAllClaims(String token) {
-		return Jwts.parser()
-			.verifyWith(getSigningKey())
-			.build()
-			.parseSignedClaims(token)
-			.getPayload();
-	}
+	private Claims extractAllClaims(String token) {
+		// Delegate to validateToken to ensure denylist check is performed
+		return validateToken(token);
+	}

This change ensures all token parsing includes denylist validation while removing code duplication.

src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java (2)

73-82: Fix null check ordering to prevent NullPointerException.

The userId null check (line 79) occurs after Integer.parseInt(userId) (line 75). If userId is null, the parseInt call will throw a NullPointerException before the null check is evaluated.

 		try {
-
 			String jwtToken = CookieUtil.getJwtTokenFromCookie(request);
+			if (jwtToken == null) {
+				response.setError(403, "Unauthorized access: Missing or invalid token");
+				return response.toString();
+			}
 			String userId = jwtUtil.getUserIdFromToken(jwtToken);
-			Integer userID=Integer.parseInt(userId);
-
-			JSONObject obj = new JSONObject(comingRequest);
-			logger.info("getUserServicePointVanDetails request " + comingRequest);
-			if (userId == null || jwtToken ==null) {
+			if (userId == null) {
 				response.setError(403, "Unauthorized access: Missing or invalid token");
 				return response.toString();
 			}
+			Integer userID = Integer.parseInt(userId);
+
+			JSONObject obj = new JSONObject(comingRequest);
+			logger.info("getUserServicePointVanDetails request " + comingRequest);
 			String responseData = iemrMmuLoginServiceImpl.getUserServicePointVanDetails(userID);
 			response.setResponse(responseData);

120-135: Same null check ordering issue as above.

The pattern is repeated here: Integer.parseInt(userId) (line 122) is called before checking if userId or jwtToken is null (lines 127, 131).

 	public String getUserVanSpDetails(@RequestBody String comingRequest, HttpServletRequest request) {
 		OutputResponse response = new OutputResponse();
 		try {
-		String jwtToken = CookieUtil.getJwtTokenFromCookie(request);
-		String userId = jwtUtil.getUserIdFromToken(jwtToken);
-		Integer userID=Integer.parseInt(userId);
-
+			String jwtToken = CookieUtil.getJwtTokenFromCookie(request);
+			if (jwtToken == null) {
+				response.setError(403, "Unauthorized access: Missing or invalid token");
+				return response.toString();
+			}
+			String userId = jwtUtil.getUserIdFromToken(jwtToken);
+			if (userId == null) {
+				response.setError(403, "Unauthorized access: Missing or invalid token");
+				return response.toString();
+			}
+			Integer userID = Integer.parseInt(userId);
+			
 			JSONObject obj = new JSONObject(comingRequest);
 			logger.info("getServicepointVillages request " + comingRequest);
 			
-			if (userId !=null  && obj.has("providerServiceMapID")) {
+			if (obj.has("providerServiceMapID")) {
 					String responseData = iemrMmuLoginServiceImpl.getUserVanSpDetails(userID,
 							obj.getInt("providerServiceMapID"));
 					response.setResponse(responseData);
-				} else if(userId == null || jwtToken ==null) {
-					response.setError(403, "Unauthorized access : Missing or invalid token");
 				} else {
 				response.setError(5000, "Invalid request");
 			}
src/main/java/com/iemr/tm/controller/common/main/WorklistController.java (1)

711-800: TC Specialist worklist endpoints are missing @PreAuthorize annotations.

The endpoints getTCSpecialistWorkListNew, getTCSpecialistWorkListNewPatientApp, and getTCSpecialistWorklistFutureScheduled (lines 711-800) lack security annotations while all other role-specific worklist endpoints have them. These should be restricted to TC_SPECIALIST role.

 @Operation(summary = "Get teleconsultation specialist worklist")
 @GetMapping(value = { "/getTCSpecialistWorklist/{providerServiceMapID}/{serviceID}" })
+@PreAuthorize("hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST')")
 public String getTCSpecialistWorkListNew(...) {

Apply similar annotations to the other two TC specialist endpoints.

♻️ Duplicate comments (3)
src/main/java/com/iemr/tm/controller/dataSyncActivity/StartSyncActivity.java (1)

50-50: Duplicate role naming issue with DATASYNC vs DATA_SYNC.

This controller has the same role naming inconsistency as MMUDataSyncVanToServer.java. See the comment on that file for details and verification steps.

src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java (1)

48-48: Duplicate role naming issue with TCSPECIALIST vs TC_SPECIALIST.

This controller has the same role naming inconsistency noted in PatientAppCommonMasterController.java (lines 135, 157, 179, 201, 223, 245). The duplication indicates unclear canonical role names.

src/main/java/com/iemr/tm/controller/labtechnician/LabtechnicianController.java (1)

27-28: Restricting lab endpoints to lab technician roles makes sense; verify role naming

The class-level @PreAuthorize("hasRole('LAB_TECHNICIAN') || hasRole('LABTECHNICIAN') ") correctly gates all lab endpoints to lab-tech roles. Just ensure that:

  • Your GrantedAuthority values align with these role strings and Spring’s hasRole convention, and
  • You really need both LAB_TECHNICIAN and LABTECHNICIAN variants long-term (or can normalize to a single canonical role).

Also applies to: 48-51

🧹 Nitpick comments (13)
src/main/java/com/iemr/tm/controller/patientApp/master/PatientAppCommonMasterController.java (1)

65-65: Remove trailing spaces in authorization expression.

The annotation string contains trailing spaces: "hasRole('NURSE') || hasRole('DOCTOR') ". While this won't affect functionality, it's inconsistent with the style used elsewhere.

Apply this diff:

-	@PreAuthorize("hasRole('NURSE') || hasRole('DOCTOR')  ")
+	@PreAuthorize("hasRole('NURSE') || hasRole('DOCTOR')")
src/main/java/com/iemr/tm/controller/nurse/vitals/AnthropometryVitalsController.java (1)

22-22: Remove trailing whitespace in @PreAuthorize expression.

The annotation contains a trailing space inside the string: "hasRole('NURSE') ". While this typically doesn't affect functionality, it's inconsistent with other controllers and should be cleaned up.

-@PreAuthorize("hasRole('NURSE') ")
+@PreAuthorize("hasRole('NURSE')")
src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java (1)

177-180: Consider de-duplicating repeated complex role expressions

Several methods repeat the same long role set (e.g. hasRole('NURSE') || hasRole('DOCTOR') || hasRole('LABTECHNICIAN') || hasRole('LAB_TECHNICIAN') || hasRole('PHARMACIST') ...). Over time this is easy to get out of sync.

If this pattern stabilizes, consider introducing:

  • A custom composed annotation (e.g. @BenReadAccess) backed by a single @PreAuthorize, or
  • At least shared constants for the SpEL strings.

This would make future role changes less error-prone.

Also applies to: 212-215, 286-290, 318-322

src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java (1)

3-4: Use DISTINCT and align role names with security layer expectations

The new getRoleNamebyUserId is straightforward, but two small points:

  • Consider SELECT DISTINCT rolename ... to avoid duplicate role names if a user has multiple service-role mappings.
  • Ensure the returned rolename values match what your security layer expects (e.g. either NURSE/DOCTOR that you later convert to ROLE_*, or already-prefixed names compatible with hasRole).

Also applies to: 18-20

src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java (1)

3-3: getUserRoles logic looks fine; fix typos and naming for clarity

The getUserRoles method correctly validates userId, delegates to UserLoginRepo, and fails fast when no roles are found. Two minor cleanups:

  • Rename role to roles (or similar) to reflect it’s a List<String>.
  • Fix typos in the exception message: "Failed to retrieverole for usedId : ...""Failed to retrieve roles for userId : ...".

These don’t affect behavior but will make logs and errors easier to interpret.

Also applies to: 134-147

src/main/java/com/iemr/tm/utils/redis/RedisStorage.java (1)

113-120: Return an empty collection instead of null.

Returning null on failure forces callers to handle null checks and risks NullPointerException. Per static analysis, return an empty list instead.

 public List<String> getUserRoleFromCache(Long userId) {
     try {
-        return redisTemplate.opsForList().range("roles:" + userId, 0, -1);
+        List<String> roles = redisTemplate.opsForList().range("roles:" + userId, 0, -1);
+        return roles != null ? roles : Collections.emptyList();
     } catch (Exception e) {
         logger.warn("Failed to retrieve cached role for user {} : {} ", userId, e.getMessage());
-        return null;
+        return Collections.emptyList();
     }
 }

Add import: import java.util.Collections;

src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java (1)

17-17: Remove unused imports.

Per static analysis, CommonMasterServiceImpl and Cookie are not used.

-import com.iemr.tm.service.common.master.CommonMasterServiceImpl;
 import com.iemr.tm.utils.CookieUtil;
...
-import jakarta.servlet.http.Cookie;
 import jakarta.servlet.http.HttpServletRequest;

Also applies to: 27-27

src/main/java/com/iemr/tm/controller/common/main/WorklistController.java (1)

110-110: Inconsistent role naming patterns suggest unclear role normalization.

The code uses both TCSPECIALIST and TC_SPECIALIST, and LABTECHNICIAN and LAB_TECHNICIAN. This duplication indicates uncertainty about how roles are stored and transformed.

The RoleAuthenticationFilter transforms roles via .toUpperCase().replace(" ", "_"), so a role stored as "TC Specialist" becomes "ROLE_TC_SPECIALIST".

Standardize role names across the codebase. If roles are consistently transformed to use underscores, you can simplify:

-@PreAuthorize("hasRole('TC_SPECIALIST') || hasRole('TCSPECIALIST') ")
+@PreAuthorize("hasRole('TC_SPECIALIST')")

Verify the actual role values in the database to determine the canonical form.

Also applies to: 157-157, 178-178, 225-225

src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java (1)

35-39: Remove dead code: CSRF token repository is configured but CSRF is disabled.

Lines 35-37 configure a CookieCsrfTokenRepository but line 39 disables CSRF entirely, making this configuration unused.

 @Bean
 public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-    CookieCsrfTokenRepository csrfTokenRepository = new CookieCsrfTokenRepository();
-    csrfTokenRepository.setCookieHttpOnly(true);
-    csrfTokenRepository.setCookiePath("/");
     http
         .csrf(csrf -> csrf.disable())
src/main/java/com/iemr/tm/controller/ncdCare/NCDCareController.java (1)

266-266: Confirm that allowing both NURSE and DOCTOR on update endpoints matches the intended access model

updateHistoryNurse and updateVitalNurse now allow both NURSE and DOCTOR, even though the JavaDoc/objective text focuses on nurse‑entered data. If domain rules require that only doctors can overwrite nurse data (or vice‑versa), you may want to tighten these to a single role or split endpoints accordingly.

If the intent is that both can perform updates, this is fine as‑is; just confirm it matches your functional requirements and threat model.

Also applies to: 304-304

src/main/java/com/iemr/tm/controller/covid19/CovidController.java (1)

258-258: Reconfirm mixed NURSE/DOCTOR write access on COVID update endpoints

updateHistoryNurse and updateVitalNurse allow both NURSE and DOCTOR while dealing with nurse‑captured data. If your policy is that only one of these roles should be able to perform these modifications, consider tightening the expression; otherwise, documenting this shared update responsibility somewhere in your security design would help future maintainers.

Also applies to: 296-296

src/main/java/com/iemr/tm/controller/generalOPD/GeneralOPDController.java (1)

298-298: Validate that allowing both NURSE and DOCTOR on General OPD update flows is intentional

updateVisitNurse, updateHistoryNurse, updateVitalNurse, and updateGeneralOPDExaminationNurse now accept both NURSE and DOCTOR. Given that the JavaDocs emphasize nurse‑entered data being potentially replaced by doctor details, double‑check that nurses are indeed supposed to retain write access once doctors are involved. If not, you may want to move some of these to DOCTOR‑only.

Also applies to: 333-333, 368-368, 403-403

src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java (1)

335-335: Double‑check that mixed NURSE/DOCTOR write access on NCD screening updates matches requirements

updateHistoryNurse, updateVitalNurse, and updateIDRSScreen all now allow both NURSE and DOCTOR. Given that some comments describe overwriting nurse data with doctor details, verify whether nurses should still be able to change these records post‑doctor‑review, or whether some of these endpoints should be DOCTOR‑only.

If the shared access is intended (e.g., for corrections), consider documenting that explicitly in your security/requirements docs.

Also applies to: 369-369, 398-398, 427-427

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb786bf and 41df6e2.

📒 Files selected for processing (31)
  • pom.xml (2 hunks)
  • src/main/java/com/iemr/tm/controller/anc/AntenatalCareController.java (15 hunks)
  • src/main/java/com/iemr/tm/controller/cancerscreening/CancerScreeningController.java (17 hunks)
  • src/main/java/com/iemr/tm/controller/common/main/WorklistController.java (38 hunks)
  • src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/covid19/CovidController.java (10 hunks)
  • src/main/java/com/iemr/tm/controller/dataSyncActivity/StartSyncActivity.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/foetalmonitor/FoetalMonitorController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/generalOPD/GeneralOPDController.java (13 hunks)
  • src/main/java/com/iemr/tm/controller/labtechnician/LabtechnicianController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/location/LocationController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/login/IemrMmuLoginController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/ncdCare/NCDCareController.java (10 hunks)
  • src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java (15 hunks)
  • src/main/java/com/iemr/tm/controller/nurse/vitals/AnthropometryVitalsController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/patientApp/master/PatientAppCommonMasterController.java (11 hunks)
  • src/main/java/com/iemr/tm/controller/pnc/PostnatalCareController.java (14 hunks)
  • src/main/java/com/iemr/tm/controller/quickconsult/QuickConsultController.java (7 hunks)
  • src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java (17 hunks)
  • src/main/java/com/iemr/tm/controller/report/CRMReportController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/snomedct/SnomedController.java (2 hunks)
  • src/main/java/com/iemr/tm/controller/teleconsultation/TeleConsultationController.java (2 hunks)
  • src/main/java/com/iemr/tm/repo/login/UserLoginRepo.java (2 hunks)
  • src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java (2 hunks)
  • src/main/java/com/iemr/tm/utils/JwtUtil.java (1 hunks)
  • src/main/java/com/iemr/tm/utils/exception/CustomAccessDeniedHandler.java (1 hunks)
  • src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java (1 hunks)
  • src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java (1 hunks)
  • src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java (1 hunks)
  • src/main/java/com/iemr/tm/utils/redis/RedisStorage.java (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/main/java/com/iemr/tm/controller/dataSyncActivity/StartSyncActivity.java (3)
src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java (1)
  • RestController (42-109)
src/main/java/com/iemr/tm/controller/labtechnician/LabtechnicianController.java (1)
  • RestController (48-154)
src/main/java/com/iemr/tm/controller/snomedct/SnomedController.java (1)
  • RequestMapping (44-107)
src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java (3)
src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java (1)
  • Component (22-148)
src/main/java/com/iemr/tm/utils/JwtUtil.java (1)
  • Component (14-77)
src/main/java/com/iemr/tm/utils/redis/RedisStorage.java (1)
  • Component (37-121)
src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java (3)
src/main/java/com/iemr/tm/utils/JwtAuthenticationUtil.java (1)
  • Component (22-148)
src/main/java/com/iemr/tm/utils/JwtUtil.java (1)
  • Component (14-77)
src/main/java/com/iemr/tm/utils/exception/CustomAccessDeniedHandler.java (1)
  • Component (14-28)
🪛 GitHub Check: SonarCloud Code Analysis
src/main/java/com/iemr/tm/utils/redis/RedisStorage.java

[warning] 99-99: Remove this field injection and use constructor injection instead.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxrxoxAzld-109w8&open=AZrDyxrxoxAzld-109w8&pullRequest=104


[warning] 118-118: Return an empty collection instead of null.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxrxoxAzld-109w9&open=AZrDyxrxoxAzld-109w9&pullRequest=104

src/main/java/com/iemr/tm/utils/mapper/RoleAuthenticationFilter.java

[failure] 33-33: "logger" is the name of a field in "GenericFilterBean".

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109xA&open=AZrDyxuCoxAzld-109xA&pullRequest=104


[warning] 35-35: Remove this field injection and use constructor injection instead.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109xB&open=AZrDyxuCoxAzld-109xB&pullRequest=104


[warning] 69-69: Extract this nested try block into a separate method.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109w_&open=AZrDyxuCoxAzld-109w_&pullRequest=104


[warning] 38-38: Remove this field injection and use constructor injection instead.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109xC&open=AZrDyxuCoxAzld-109xC&pullRequest=104


[warning] 27-27: Remove this unused import 'jakarta.servlet.http.Cookie'.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109xG&open=AZrDyxuCoxAzld-109xG&pullRequest=104


[warning] 17-17: Remove this unused import 'com.iemr.tm.service.common.master.CommonMasterServiceImpl'.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109xF&open=AZrDyxuCoxAzld-109xF&pullRequest=104


[warning] 84-84: Replace this usage of 'Stream.collect(Collectors.toList())' with 'Stream.toList()' and ensure that the list is unmodified.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109xE&open=AZrDyxuCoxAzld-109xE&pullRequest=104


[warning] 41-41: Remove this field injection and use constructor injection instead.

See more on https://sonarcloud.io/project/issues?id=PSMRI_TM-API&issues=AZrDyxuCoxAzld-109xD&open=AZrDyxuCoxAzld-109xD&pullRequest=104

🔇 Additional comments (15)
src/main/java/com/iemr/tm/controller/anc/AntenatalCareController.java (1)

70-70: LGTM - Appropriate role restrictions for ANC workflow.

The access control logic correctly restricts:

  • Nurse data saving to NURSE role only (line 70)
  • Doctor data saving to DOCTOR role only (lines 103, 445)
  • Read and update operations to both NURSE and DOCTOR roles

This properly enforces the ANC workflow separation of concerns.

Minor style note: Several annotations have trailing spaces in the string (lines 138, 165, 192, 218, 245, 271, 300, 329, 358, 387, 416), e.g., "hasRole('NURSE') || hasRole('DOCTOR') ". Consider removing for consistency.

src/main/java/com/iemr/tm/controller/snomedct/SnomedController.java (1)

46-46: LGTM - Appropriate access control for clinical terminology.

Restricting SNOMED CT clinical terminology access to NURSE and DOCTOR roles is appropriate for this medical records system.

Minor style note: The annotation has a trailing space: "hasRole('NURSE') || hasRole('DOCTOR') ". Consider removing for consistency.

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

74-74: LGTM - Well-designed access control for cancer screening workflow.

The role-based access control is appropriately structured:

  • Nurse data entry restricted to NURSE role (line 74)
  • Doctor updates restricted to DOCTOR role (lines 111, 579)
  • Shared read/update operations allow NURSE and DOCTOR
  • Cancer diagnosis updates appropriately include ONCOLOGIST role (line 544)

This properly enforces the cancer screening clinical workflow with appropriate specialist involvement.

src/main/java/com/iemr/tm/utils/exception/CustomAccessDeniedHandler.java (1)

14-27: LGTM!

Clean implementation that follows the same pattern as CustomAuthenticationEntryPoint. The static ObjectMapper is thread-safe, and the generic error message avoids leaking sensitive exception details.

src/main/java/com/iemr/tm/controller/report/CRMReportController.java (1)

49-50: This role naming pattern is systematic across the codebase, not isolated to CRMReportController.

Both role variants (LABTECHNICIAN/LAB_TECHNICIAN and TCSPECIALIST/TC_SPECIALIST) appear consistently together in @PreAuthorize annotations across 8+ controller files (LabtechnicianController, TeleConsultationController, CRMReportController, LocationController, IemrMmuLoginController, WorklistController, and others). This suggests intentional dual support—likely for backward compatibility—rather than an inconsistency requiring immediate standardization in this specific file.

If standardization is desired, it must be addressed codebase-wide. Alternatively, if this is intentional legacy support, document it centrally and verify both role variants are actually recognized by the authentication layer.

src/main/java/com/iemr/tm/controller/pnc/PostnatalCareController.java (1)

28-29: Confirm role naming vs hasRole expectations and document access rules

The added @PreAuthorize annotations on PNC endpoints look consistent with the intended nurse/doctor responsibilities, but correctness depends on how authorities are populated:

  • hasRole('NURSE') / hasRole('DOCTOR') expect GrantedAuthority values like ROLE_NURSE, ROLE_DOCTOR by default.
  • If your JWT/RoleAuthenticationFilter currently uses bare role names (e.g. NURSE), either:
    • Adjust authority creation to prefix with ROLE_, or
    • Switch these to hasAuthority('NURSE') / hasAuthority('DOCTOR').

It would also help to explicitly document (in SecurityConfig or constants) which roles are allowed per screen so future additions (e.g. new clinical roles) stay consistent.

Also applies to: 68-71, 106-109, 139-142, 172-176, 205-208, 236-239, 268-271, 299-303, 327-330, 363-366, 399-402, 435-438, 464-467

src/main/java/com/iemr/tm/controller/quickconsult/QuickConsultController.java (1)

28-29: Validate that quick consult authorities line up with hasRole usage

The new @PreAuthorize guards for nurse-only, doctor-only, and shared quick-consult endpoints are reasonable. As with other controllers, please verify:

  • Authorities derived from JWT/DB are named to match hasRole('NURSE') / hasRole('DOCTOR') (i.e. underlying authorities should typically be ROLE_NURSE / ROLE_DOCTOR), or
  • If authorities are stored as plain NURSE / DOCTOR, update these expressions to hasAuthority(...) instead.

Once verified, this controller’s access control looks good.

Also applies to: 77-80, 114-117, 153-156, 184-187, 216-220, 244-247

src/main/java/com/iemr/tm/controller/registrar/main/RegistrarController.java (1)

32-33: Ensure registrar role strings align with actual authorities, especially LAB variants*

You’ve added comprehensive @PreAuthorize checks with combinations of NURSE, DOCTOR, REGISTRAR, LABTECHNICIAN / LAB_TECHNICIAN, and PHARMACIST. Functionally this looks right for registrar/search/beneficiary and lab/pharmacy-facing endpoints.

To avoid silent denials:

  • Confirm which exact role names are stored for users (e.g. LABTECHNICIAN vs LAB_TECHNICIAN), and that your GrantedAuthority values conform to Spring’s hasRole convention (ROLE_…), or else switch to hasAuthority.
  • Double-check that endpoints intended for both lab & pharmacy access (e.g. beneficiary image/details) include all required roles and no unintended ones.

Also applies to: 84-88, 104-108, 124-127, 147-150, 177-180, 212-215, 238-242, 264-266, 286-290, 318-322, 336-339, 399-403, 418-421, 481-485, 504-507, 528-531

src/main/java/com/iemr/tm/controller/common/master/CommonMasterController.java (1)

29-30: Confirm that restricting /master APIs to NURSE/DOCTOR won’t break other role flows

Adding class-level @PreAuthorize("hasRole('NURSE') || hasRole('DOCTOR') ") is consistent with the current method names (nurse/doctor master data), but it will deny access for any existing Registrar, LabTechnician, etc. clients calling these endpoints.

Please:

  • Verify no non-nurse/doctor flows depend on /master/**.
  • As elsewhere, ensure your authorities are aligned with hasRole semantics, or switch to hasAuthority if you don’t use the ROLE_ prefix convention.

Also applies to: 42-46

src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java (1)

15-22: I'll help you verify this review comment. Let me start by examining the relevant code files to confirm the issues and assess the recommendations.
<function_calls>


#!/bin/bash

Find and read the CustomAuthenticationEntryPoint file

find . -name "CustomAuthenticationEntryPoint.java" -type f


</function_calls>
<function_calls>


#!/bin/bash

Also search for CustomAccessDeniedHandler to verify if it's a comparable pattern

find . -name "CustomAccessDeniedHandler.java" -type f


</function_calls>
<function_calls>


#!/bin/bash

Search for exception handling utilities

find . -name "Exception.java" -type f | head -20


</function_calls>

Let me execute these searches:
<function_calls>


#!/bin/bash

Locate the file mentioned in the review

cat src/main/java/com/iemr/tm/utils/exception/CustomAuthenticationEntryPoint.java 2>/dev/null || echo "File not found at expected path"


</function_calls>

src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java (1)

41-43: I'll help you verify the security configuration concerns. Let me search the codebase for actuator, Swagger, and related configurations.
<function_calls>

#!/bin/bash

Search for actuator and swagger references in the codebase

echo "=== Searching for actuator/swagger references ==="
rg -n "actuator|swagger|springdoc" --type=java --type=properties --type=yaml -A 2 -B 2


</function_calls>

#!/bin/bash

Read the full SecurityConfig.java file

echo "=== Reading SecurityConfig.java ==="
cat -n src/main/java/com/iemr/tm/utils/mapper/SecurityConfig.java


</function_calls>

#!/bin/bash

Search for application configuration files

echo "=== Looking for application config files ==="
find . -type f ( -name "application.properties" -o -name "application.yml" -o -name "application-.properties" -o -name "application-.yml" ) 2>/dev/null | head -20


</function_calls>

#!/bin/bash

Check for any web endpoints or controllers that might be public

echo "=== Searching for RestController or RequestMapping ==="
rg -n "RestController|RequestMapping|GetMapping|PostMapping" --type=java -A 3 | head -50


</function_calls>

src/main/java/com/iemr/tm/controller/ncdCare/NCDCareController.java (1)

31-31: RBAC mapping across NCD Care endpoints looks coherent; please confirm authority naming and method-security config

  • saveBenNCDCareNurseData restricted to hasRole('NURSE') and saveBenNCDCareDoctorData/updateNCDCareDoctorData to hasRole('DOCTOR') align well with their responsibilities.
  • Read-style endpoints (getBenVisitDetailsFrmNurseNCDCare, history, vitals, doctor case record) and mixed nurse/doctor update endpoints are guarded with hasRole('NURSE') || hasRole('DOCTOR'), which matches the naming/comments.

Two things to double‑check:

  1. In Spring Security 6/Boot 3, hasRole('X') expects a GrantedAuthority of ROLE_X by default. Ensure your authentication setup issues ROLE_NURSE / ROLE_DOCTOR (or that you’ve customized the role prefix), otherwise these checks will silently fail.
  2. Verify that global method security is enabled (e.g. @EnableMethodSecurity(prePostEnabled = true) or equivalent) so these @PreAuthorize annotations are actually enforced.

Also applies to: 73-73, 110-110, 143-143, 175-175, 206-206, 239-239, 266-266, 304-304, 339-339

src/main/java/com/iemr/tm/controller/covid19/CovidController.java (1)

31-31: Consistent nurse/doctor RBAC for COVID endpoints; verify GrantedAuthority values and method security

  • saveBenNCDCareNurseData guarded by hasRole('NURSE') and saveBenCovidDoctorData/updateCovid19DoctorData by hasRole('DOCTOR') is consistent with the intent.
  • Read and detail endpoints (visit, history, vitals, case‑record) and most update flows are hasRole('NURSE') || hasRole('DOCTOR'), which matches their names and usage.

Same Spring Security points to validate:

  1. That your Authentication contains ROLE_NURSE / ROLE_DOCTOR (or that you’ve customized the role prefix) so hasRole('...') behaves as expected.
  2. That method security is enabled at configuration level so @PreAuthorize is applied.

Also applies to: 65-65, 102-102, 135-135, 167-167, 198-198, 231-231, 258-258, 296-296, 331-331

src/main/java/com/iemr/tm/controller/generalOPD/GeneralOPDController.java (1)

28-28: General OPD RBAC is aligned with endpoint responsibilities; ensure authorities and method security are wired

  • saveBenGenOPDNurseData restricted to hasRole('NURSE') and saveBenGenOPDDoctorData / updateGeneralOPDDoctorData to hasRole('DOCTOR') is appropriate.
  • All read‑style and shared nurse/doctor flows (visit, history, vitals, examination, case record) use hasRole('NURSE') || hasRole('DOCTOR'), which matches the controller semantics.

As with other controllers, please confirm:

  1. Your authorities use the ROLE_ prefix (e.g., ROLE_NURSE, ROLE_DOCTOR) or that you’ve customized Spring Security’s role prefix so hasRole('...') checks succeed.
  2. Global method security is enabled so @PreAuthorize constraints on this controller are enforced.

Also applies to: 74-74, 111-111, 143-143, 176-176, 207-207, 239-239, 271-271, 298-298, 333-333, 368-368, 403-403, 437-437

src/main/java/com/iemr/tm/controller/ncdscreening/NCDScreeningController.java (1)

28-28: NCD Screening RBAC rules are consistent and granular; please verify authority values and method-security setup

  • saveBeneficiaryNCDScreeningDetails and updateBeneficiaryNCDScreeningDetails are NURSE‑only, which fits their nurse‑focused responsibilities.
  • Doctor‑specific flows (saveBenNCDScreeningDoctorData, updateDoctorData) are DOCTOR‑only, which is appropriate.
  • Data retrieval endpoints (visit, history, vitals, IDRS, case‑records, visit count) are accessible to both NURSE and DOCTOR, matching their usage in shared workflows.
  • Shared update flows for history, vitals, and IDRS also permit both roles.

As with the other controllers:

  1. Confirm that your GrantedAuthority values follow the ROLE_NURSE/ROLE_DOCTOR convention (or that you’ve overridden the default role prefix) so that hasRole('NURSE') / hasRole('DOCTOR') function correctly under Spring Security 6 / Boot 3.2.2.
  2. Ensure method‑level security is enabled (e.g., via @EnableMethodSecurity) so these @PreAuthorize annotations are active in production.

Also applies to: 79-79, 111-111, 143-143, 169-169, 198-198, 226-226, 253-253, 279-279, 306-306, 335-335, 369-369, 398-398, 427-427, 456-456

Copy link
Member

@drtechie drtechie left a comment

Choose a reason for hiding this comment

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

Approving, please check the comments if relevant

@vanitha1822
Copy link
Contributor Author

CSRF disabled because app uses token-based REST APIs.

@vanitha1822 vanitha1822 reopened this Nov 27, 2025
@vanitha1822 vanitha1822 merged commit 2e76160 into release-3.6.1 Nov 27, 2025
3 of 4 checks passed
@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot
25.7% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

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.

3 participants