Skip to content

Conversation

@kevalkanp1011
Copy link

@kevalkanp1011 kevalkanp1011 commented Apr 2, 2025

πŸ“‹ Description

JIRA ID:

Please provide a summary of the change and the motivation behind it. Include relevant context and details.


βœ… 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
    • Enhanced authentication with token-based and secure cookie management for a safer and more reliable login experience.
    • Improved user session handling with faster, seamless access across the application.
    • Strengthened overall security measures to ensure robust and consistent validation of user credentials.
    • Added dynamic and configurable Cross-Origin Resource Sharing (CORS) support for flexible and secure resource sharing.
    • Introduced detailed user identity management and validation for improved user data handling and security.

@coderabbitai
Copy link

coderabbitai bot commented Apr 2, 2025

Walkthrough

The pull request adds new project dependencies and multiple Java classes to enable JSON processing and JWT-based authentication. Enhancements include a new user entity with its repository interface, and several utility classes for handling cookies, generating and validating JWT tokens. Additionally, a servlet filter along with its configuration is introduced to intercept HTTP requests and enforce JWT validation. CORS configuration is centralized and dynamic CORS filtering is implemented. Cross-origin annotations are removed from controllers, and new environment properties for CORS allowed origins are added.

Changes

File(s) Change Summary
pom.xml Added new dependencies for Jersey JSON Processing, JAXB Runtime, and JWT (jjwt-api, jjwt-impl with runtime scope, jjwt-jackson with runtime scope).
Domain & Repository Added M_User.java (new JPA entity mapping to the m_User table) and EmployeeMasterRepo.java (new Spring Data repository with methods findByUserID and getUserByUserID for CRUD operations).
utils (CookieUtil, FilterConfig, JwtAuthenticationUtil, JwtUserIdValidationFilter, JwtUtil, DynamicCorsFilter) Introduced utility classes: CookieUtil for cookie operations related to JWT, FilterConfig for registering the JWT validation filter, JwtAuthenticationUtil for validating tokens and user IDs (with caching and DB fallback), JwtUserIdValidationFilter to intercept and validate requests, JwtUtil for token generation and claim extraction, and DynamicCorsFilter for dynamic CORS handling.
config (CorsConfig) Added CorsConfig class implementing WebMvcConfigurer to configure CORS globally with allowed origins from properties, allowed methods, headers, credentials, and exposed headers.
controller (IdentityController, FamilyTaggingController, VersionController) Removed all @CrossOrigin annotations from controller classes and methods to centralize CORS handling.
environment properties Added cors.allowed-origins property to multiple environment configuration files, either empty or set from environment variables, to support CORS configuration.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant F as JwtUserIdValidationFilter
    participant CU as CookieUtil
    participant JA as JwtAuthenticationUtil
    participant DB as EmployeeMasterRepo
    participant RC as Redis Cache

    C->>F: Send HTTP request with JWT (cookie/header)
    F->>CU: Extract JWT token from request
    CU-->>F: Return extracted token
    F->>JA: Validate JWT token
    alt Token valid
        JA->>RC: Check if user data is cached
        alt User not found in cache
            JA->>DB: Retrieve user details from DB
            DB-->>JA: Return user information
            JA->>RC: Cache user data
        end
        JA-->>F: Return success response
    else Token invalid
        JA-->>F: Return error response
    end
    F->>C: Proceed with request / Return unauthorized error
Loading

Poem

Oh, what a joyful night,
I hopped to see new code light,
JWT tokens bouncing in the breeze,
Cookies and filters working with ease,
CORS now dances on a dynamic stage,
Controllers freed from their old cage,
My whiskers twitch at every line,
Celebrating changes that now shine!
🐰✨

Note

⚑️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚑️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boostβ€”your workflow just got faster.


πŸ“œ Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between b2b234e and f922e5c.

πŸ“’ Files selected for processing (15)
  • src/main/environment/1097_ci.properties (1 hunks)
  • src/main/environment/1097_dev.properties (1 hunks)
  • src/main/environment/1097_example.properties (1 hunks)
  • src/main/environment/1097_test.properties (1 hunks)
  • src/main/environment/1097_uat.properties (1 hunks)
  • src/main/environment/common_ci.properties (1 hunks)
  • src/main/environment/common_dev.properties (1 hunks)
  • src/main/environment/common_example.properties (1 hunks)
  • src/main/environment/common_test.properties (1 hunks)
  • src/main/environment/common_uat.properties (1 hunks)
  • src/main/java/com/iemr/common/identity/config/CorsConfig.java (1 hunks)
  • src/main/java/com/iemr/common/identity/controller/IdentityController.java (21 hunks)
  • src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java (6 hunks)
  • src/main/java/com/iemr/common/identity/controller/version/VersionController.java (1 hunks)
  • src/main/java/com/iemr/common/identity/utils/DynamicCorsFilter.java (1 hunks)
βœ… Files skipped from review due to trivial changes (11)
  • src/main/environment/1097_dev.properties
  • src/main/environment/common_test.properties
  • src/main/environment/common_uat.properties
  • src/main/environment/common_example.properties
  • src/main/environment/common_dev.properties
  • src/main/environment/1097_example.properties
  • src/main/environment/1097_uat.properties
  • src/main/environment/1097_test.properties
  • src/main/environment/common_ci.properties
  • src/main/environment/1097_ci.properties
  • src/main/java/com/iemr/common/identity/controller/familyTagging/FamilyTaggingController.java
πŸ”‡ Additional comments (4)
src/main/java/com/iemr/common/identity/controller/version/VersionController.java (1)

44-44: Cross-Origin annotation removed as part of centralized CORS configuration

This change is part of a broader strategy to centralize CORS configuration. The removed @CrossOrigin() annotation has been replaced by a global CORS configuration through the new CorsConfig class and DynamicCorsFilter.

src/main/java/com/iemr/common/identity/controller/IdentityController.java (1)

85-85: Cross-Origin annotations removed from all controller methods

The removal of all @CrossOrigin(origins = { "*commonapi*" }) annotations from controller methods is consistent with moving to a centralized CORS configuration approach. This improves maintainability by defining CORS policies in a single location rather than scattered throughout the codebase.

Also applies to: 114-114, 139-139, 174-174, 205-205, 237-237, 269-269, 299-299, 324-324, 344-344, 378-378, 510-510, 617-617, 637-637, 663-663, 695-695, 794-794, 818-818, 832-832, 959-959, 974-974

src/main/java/com/iemr/common/identity/config/CorsConfig.java (1)

1-25: New centralized CORS configuration implementation

This class implements a global CORS configuration using Spring's WebMvcConfigurer. The configuration:

  • Uses externalized configuration for allowed origins, improving flexibility across environments
  • Permits necessary HTTP methods for a RESTful API
  • Explicitly exposes the "Authorization" and "Jwttoken" headers needed for JWT authentication
  • Sets appropriate security headers for CORS

This is a recommended approach for managing CORS in Spring applications and aligns with the PR objective of enhancing middleware configuration.

src/main/java/com/iemr/common/identity/utils/DynamicCorsFilter.java (1)

1-38: New filter for dynamic CORS header management

This filter complements the CorsConfig class by handling CORS headers at the filter level, particularly beneficial for:

  • Dynamically setting the Access-Control-Allow-Origin header based on the request's Origin
  • Efficiently handling preflight OPTIONS requests without engaging the full filter chain
  • Providing an additional layer of CORS handling for requests that might bypass the Spring MVC handling

The implementation follows best practices for servlet filters by extending OncePerRequestFilter to prevent duplicate processing of forwarded requests.

However, there appears to be potential duplication of CORS handling between this filter and the CorsConfig class. You may want to:

  1. Document the specific scenarios where each approach is needed
  2. Verify that both configurations use the same allowed origins to maintain consistency
✨ Finishing Touches
  • πŸ“ Generate Docstrings

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
πŸͺ§ Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Apr 2, 2025

Quality Gate Failed Quality Gate failed

Failed conditions
4.1% Duplication on New Code (required ≀ 3%)

See analysis details on SonarQube Cloud

Copy link

@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: 8

🧹 Nitpick comments (12)
src/main/java/com/iemr/common/identity/repo/iemr/EmployeeMasterRepo.java (1)

8-11: Consider consolidating redundant methods.

The interface defines two methods (findByUserID and getUserByUserID) that appear to perform the same function - retrieving a user by ID. Spring Data JPA will automatically implement findByUserID based on naming convention, making the second method potentially redundant.

If these methods serve different purposes (e.g., different query implementations), consider:

  1. Adding documentation to clarify their distinct roles
  2. Or consolidating into a single method if they're functionally identical
@Repository
public interface EmployeeMasterRepo extends JpaRepository<M_User,Integer> {
    M_User findByUserID(Integer userID);

-    M_User getUserByUserID(Integer parseLong);
}
src/main/java/com/iemr/common/identity/utils/FilterConfig.java (1)

7-18: Add documentation and consider filter ordering.

The configuration correctly registers the JWT validation filter, but lacks documentation about its purpose and behavior.

Consider adding:

  1. Javadoc comments explaining the filter's purpose
  2. Filter ordering to control execution sequence if multiple filters exist
  3. Conditional activation through properties
@Configuration
+/**
+ * Configuration for JWT token validation filter.
+ * Registers a filter that intercepts all requests to validate JWT tokens.
+ */
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<JwtUserIdValidationFilter> jwtUserIdValidationFilter(
            JwtAuthenticationUtil jwtAuthenticationUtil) {
        FilterRegistrationBean<JwtUserIdValidationFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil));
        registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints
+       registrationBean.setOrder(1); // Set filter order
        return registrationBean;
    }
}
src/main/java/com/iemr/common/identity/domain/iemr/M_User.java (2)

132-134: Remove TODO comments from constructors.

Both constructors contain TODO placeholder comments that should be resolved or removed before merging. These comments don't provide any information and suggest incomplete implementation.

public M_User() {
-    // TODO Auto-generated constructor stub
}

public M_User(Integer userID, String userName) {
-    // TODO Auto-generated constructor stub
    this.userID=userID;
    this.userName=userName;
}

Also applies to: 137-138


18-133: Follow Java naming conventions for field names.

Several field names don't follow standard Java naming conventions, which typically use camelCase starting with lowercase. Current fields like dOB, dOJ, and pAN use unconventional capitalization patterns.

While these likely match the database column names, consider using proper Java naming conventions in the entity class:

    @Expose
    @Column(name="DOB")
-    private LocalDate dOB;
+    private LocalDate dob;

    @Expose
    @Column(name="DOJ")
-    private LocalDate dOJ;
+    private LocalDate doj;

    @Expose
    @Column(name="PAN")
-    private String pAN;
+    private String pan;

You can maintain the correct column mapping via the @Column annotation while using proper Java conventions.

pom.xml (1)

215-220: Remove explicit spring-web version override.

The project explicitly specifies version 6.1.12 for spring-web, which could override the version managed by Spring Boot parent. This can lead to version conflicts if not carefully managed.

Unless there's a specific reason to use this version, let Spring Boot manage the version:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
-    <version>6.1.12</version>
</dependency>
src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java (4)

22-29: Adopt a consistent dependency injection approach.
Mixing field-level @Autowired injection (lines 22-29) with constructor injection (lines 32-35) can be confusing. You should pick one pattern (preferably constructor injection) to ensure clarity and easier testability.


37-62: Avoid returning ResponseEntity from a utility method.
Returning a Spring ResponseEntity from a utility class fuses your business logic with the web layer. Instead, consider throwing a custom exception or returning a domain object, leaving HTTP-related formatting to the controller/filter layer.


64-90: Consider validating additional user attributes.
Right now, you only verify the user's existence. If needed, ensure you also confirm the user's active status or not locked/disabled in the database to enhance security.


105-123: Make parse errors more explicit.
When Integer.parseInt(userId) fails, it is wrapped in a generic exception. Consider catching NumberFormatException or validating userId before parsing for clearer error handling.

src/main/java/com/iemr/common/identity/utils/JwtUtil.java (3)

18-19: Secure your JWT secret key properly

The SECRET_KEY field stores sensitive information and should be handled carefully. Consider making it final for immutability once initialized.

-    private String SECRET_KEY;
+    private final String SECRET_KEY;

Additionally, verify the secret key is sufficiently complex and long enough (at least 256 bits for HS256) in your application properties.


56-74: Fix whitespace and improve error handling in extractUserId method

There are inconsistent whitespaces in this method and the error message could be more specific.

-public Integer extractUserId(String  jwtToken) throws IEMRException {
+public Integer extractUserId(String jwtToken) throws IEMRException {
    try {
        // Validate JWT token and extract claims
        Claims claims = validateToken(jwtToken);

        if (claims == null) {
-            throw new IEMRException("Invalid JWT token.");
+            throw new IEMRException("Invalid or expired JWT token.");
        }

        String userId = claims.get("userId", String.class);

-        return  Integer.parseInt(userId);
+        return Integer.parseInt(userId);

    } catch (NumberFormatException e) {
+        throw new IEMRException("Invalid userId format in JWT token: " + e.getMessage(), e);
    } catch (Exception e) {
        throw new IEMRException("Validation error: " + e.getMessage(), e);
    }
}

31-40: Consider adding token refresh functionality

The current implementation sets a fixed 24-hour expiration time for tokens, but doesn't provide a way to refresh tokens.

Consider adding a refresh token mechanism to improve security while maintaining user convenience. This typically involves:

  1. Generating a separate refresh token with longer expiration
  2. Adding a method to validate refresh tokens and generate new access tokens
  3. Storing refresh token identifiers in a database or cache to allow revocation

This approach allows for shorter-lived access tokens with the ability to generate new ones without requiring users to re-authenticate.

πŸ“œ Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 76dafa6 and b2b234e.

πŸ“’ Files selected for processing (8)
  • pom.xml (1 hunks)
  • src/main/java/com/iemr/common/identity/domain/iemr/M_User.java (1 hunks)
  • src/main/java/com/iemr/common/identity/repo/iemr/EmployeeMasterRepo.java (1 hunks)
  • src/main/java/com/iemr/common/identity/utils/CookieUtil.java (1 hunks)
  • src/main/java/com/iemr/common/identity/utils/FilterConfig.java (1 hunks)
  • src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java (1 hunks)
  • src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java (1 hunks)
  • src/main/java/com/iemr/common/identity/utils/JwtUtil.java (1 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java (2)
src/main/java/com/iemr/common/identity/utils/JwtUtil.java (1)
  • Component (15-85)
src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java (1)
  • Component (13-106)
src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java (2)
src/main/java/com/iemr/common/identity/utils/JwtAuthenticationUtil.java (1)
  • Component (19-124)
src/main/java/com/iemr/common/identity/utils/JwtUtil.java (1)
  • Component (15-85)
πŸͺ› ast-grep (0.31.1)
src/main/java/com/iemr/common/identity/utils/CookieUtil.java

[warning] 33-33: A cookie was detected without setting the 'secure' flag. The 'secure' flag for cookies prevents the client from transmitting the cookie over insecure channels such as HTTP. Set the 'secure' flag by calling '.setSecure(true);'.
Context: response.addCookie(cookie);
Note: [CWE-614] Sensitive Cookie in HTTPS Session Without 'Secure' Attribute. [REFERENCES]
- https://owasp.org/www-community/controls/SecureCookieAttribute

(cookie-missing-secure-flag-java)


[warning] 33-33: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: response.addCookie(cookie);
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)

src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java

[warning] 103-103: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: response.addCookie(cookie);
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)

πŸ”‡ Additional comments (1)
src/main/java/com/iemr/common/identity/utils/FilterConfig.java (1)

15-15: Verify if filtering all URLs is appropriate.

The current configuration applies JWT validation to all URLs including static resources with the pattern "/*". Verify if this is intentional or if the filter should target only specific API endpoints.

Consider restricting the filter to only API endpoints if authentication isn't required for all resources:

-        registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints
+        registrationBean.addUrlPatterns("/api/*"); // Apply filter only to API endpoints

Comment on lines +64 to +66
@Expose
@Column(name="Password")
private String password;
Copy link

@coderabbitai coderabbitai bot Apr 2, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Secure sensitive information storage.

The password field is currently exposed via the @Expose annotation, which means it could be included in serialized output. Additionally, there's no indication the password is being stored securely (hashed and salted).

Consider:

  1. Removing @Expose annotation from the password field
  2. Add a comment or annotation indicating password handling mechanism
  3. Ensure the actual storage implementation follows security best practices for passwords
-    @Expose
    @Column(name="Password")
    private String password;
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Expose
@Column(name="Password")
private String password;
@Column(name="Password")
private String password;

Copy link
Member

Choose a reason for hiding this comment

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

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Comment on lines +222 to +227
<!-- Jersey JSON Processing -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-processing</artifactId>
<version>2.30.1</version>
</dependency>
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Update Jersey JSON Processing version for compatibility.

The version of jersey-media-json-processing (2.30.1) is outdated and may have compatibility issues with Spring Boot 3.x and Jakarta EE.

Consider updating to a version that supports Jakarta EE:

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-processing</artifactId>
-    <version>2.30.1</version>
+    <version>3.1.3</version>
</dependency>
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<!-- Jersey JSON Processing -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-processing</artifactId>
<version>2.30.1</version>
</dependency>
<!-- Jersey JSON Processing -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-processing</artifactId>
<version>3.1.3</version>
</dependency>

Comment on lines +230 to +234
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Update JAXB Runtime version for compatibility.

The project is using JAXB Runtime 2.3.1, which is quite old and may not be fully compatible with Jakarta EE in Spring Boot 3.x. Spring Boot 3 uses Jakarta EE 9+ which requires newer JAXB versions.

Consider updating to a newer version that aligns with Jakarta EE:

<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
-    <version>2.3.1</version>
+    <version>4.0.0</version>
</dependency>
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>4.0.0</version>
</dependency>

Comment on lines +25 to +35
public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response, HttpServletRequest request) {
// Create a new cookie with the JWT token
Cookie cookie = new Cookie("Jwttoken", Jwttoken);
cookie.setHttpOnly(true); // Prevent JavaScript access for security
cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time
cookie.setPath("/"); // Make the cookie available for the entire application
if ("https".equalsIgnoreCase(request.getScheme())) {
cookie.setSecure(true); // Secure flag only on HTTPS
}
response.addCookie(cookie); // Add the cookie to the response
}
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Add CSRF mitigation measures to cookies.
While you already set HttpOnly and conditionally set Secure, consider adding the SameSite attribute to prevent CSRF attacks. For modern Java Servlet APIs, you may need custom headers or frameworks that support setting SameSite=Lax or Strict.

🧰 Tools
πŸͺ› ast-grep (0.31.1)

[warning] 33-33: A cookie was detected without setting the 'secure' flag. The 'secure' flag for cookies prevents the client from transmitting the cookie over insecure channels such as HTTP. Set the 'secure' flag by calling '.setSecure(true);'.
Context: response.addCookie(cookie);
Note: [CWE-614] Sensitive Cookie in HTTPS Session Without 'Secure' Attribute. [REFERENCES]
- https://owasp.org/www-community/controls/SecureCookieAttribute

(cookie-missing-secure-flag-java)


[warning] 33-33: The application does not appear to verify inbound requests which can lead to a Cross-site request forgery (CSRF) vulnerability. If the application uses cookie-based authentication, an attacker can trick users into sending authenticated HTTP requests without their knowledge from any arbitrary domain they visit. To prevent this vulnerability start by identifying if the framework or library leveraged has built-in features or offers plugins for CSRF protection. CSRF tokens should be unique and securely random. The Synchronizer Token or Double Submit Cookie patterns with defense-in-depth mechanisms such as the sameSite cookie flag can help prevent CSRF. For more information, see: [Cross-site request forgery prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Req\ uest_Forgery_Prevention_Cheat_Sheet.html).
Context: response.addCookie(cookie);
Note: [CWE-352] Cross-Site Request Forgery (CSRF). [REFERENCES]
- https://stackoverflow.com/questions/42717210/samesite-cookie-in-java-application

(cookie-missing-samesite-java)

Comment on lines +23 to +84
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;

String path = request.getRequestURI();
String contextPath = request.getContextPath();
logger.info("JwtUserIdValidationFilter invoked for path: " + path);

// Log cookies for debugging
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("userId".equals(cookie.getName())) {
logger.warn("userId found in cookies! Clearing it...");
clearUserIdCookie(response); // Explicitly remove userId cookie
}
}
} else {
logger.info("No cookies found in the request");
}

// Log headers for debugging
String jwtTokenFromHeader = request.getHeader("Jwttoken");
logger.info("JWT token from header: ");

// Skip login and public endpoints
if (path.equals(contextPath + "/user/userAuthenticate")
|| path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession")
|| path.startsWith(contextPath + "/public")) {
logger.info("Skipping filter for path: " + path);
filterChain.doFilter(servletRequest, servletResponse);
return;
}

try {
// Retrieve JWT token from cookies
String jwtTokenFromCookie = getJwtTokenFromCookies(request);
logger.info("JWT token from cookie: ");

// Determine which token (cookie or header) to validate
String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader;
if (jwtToken == null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token not found in cookies or headers");
return;
}

// Validate JWT token and userId
boolean isValid = jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken);

if (isValid) {
// If token is valid, allow the request to proceed
filterChain.doFilter(servletRequest, servletResponse);
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token");
}
} catch (Exception e) {
logger.error("Authorization error: ", e);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: ");
}
}
Copy link

@coderabbitai coderabbitai bot Apr 2, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue

Implement CSRF protection.
This filter enforces JWT validation but does not address CSRF. Attackers can forge user requests since cookies are implicitly sent with each request. Consider introducing a CSRF token mechanism, SameSite cookies, or additional server-side checks.

Copy link
Member

Choose a reason for hiding this comment

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

Cookies are set as SameSite

Copy link

Choose a reason for hiding this comment

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

🧩 Analysis chain

The code in CookieUtil.java shows that cookies are indeed being created, but I need to verify if they have the SameSite attribute set:

Let me check the content of the addJwtTokenToCookie method more carefully to see how cookies are configured:

@drtechie I looked through the codebase but couldn't find where the SameSite attribute is being set on cookies. In the CookieUtil class, the addJwtTokenToCookie method creates cookies but doesn't appear to configure the SameSite attribute.

To properly set SameSite, you could add something like:

Cookie cookie = new Cookie("Jwttoken", Jwttoken);
cookie.setHttpOnly(true);
cookie.setMaxAge(24 * 60 * 60); // 1 day
cookie.setPath("/");
if (request.isSecure()) {
    cookie.setSecure(true);
}
// Add SameSite attribute
cookie.setAttribute("SameSite", "Strict"); // or "Lax" depending on your requirements

This would strengthen CSRF protection as mentioned in the previous comment. Is this configured somewhere else in the application?


🏁 Script executed:

#!/bin/bash
# Check if CookieUtil.java exists and view its content
fd -t f "CookieUtil.java" --exec cat {} \;

Length of output: 1679


🏁 Script executed:

#!/bin/bash
# Look specifically for SameSite attribute being set in CookieUtil or related classes
rg -i "samesite" --include "*.java"

Length of output: 477


🏁 Script executed:

#!/bin/bash
# Look for cookie creation and configuration in CookieUtil
rg -A 15 "addJwtTokenToCookie" --include "*.java"

Length of output: 491


🏁 Script executed:

#!/bin/bash
# Look specifically for SameSite attribute being set in any Java file
rg -i "samesite"

# Try to find cookie configuration in the codebase
rg "cookie\.set"

Length of output: 1023


🏁 Script executed:

#!/bin/bash
# Look for the clearUserIdCookie method implementation
rg -A 10 "clearUserIdCookie" 

Length of output: 2220


@drtechie I've checked the codebase but couldn't find where the SameSite attribute is being set on cookies. In both CookieUtil.java and JwtUserIdValidationFilter.java, the cookies are configured with HttpOnly, Secure, and Path attributes, but there's no SameSite configuration.

To properly implement SameSite cookies and address the CSRF concern, you could add:

// In CookieUtil.java - addJwtTokenToCookie method
Cookie cookie = new Cookie("Jwttoken", Jwttoken);
cookie.setHttpOnly(true);
cookie.setMaxAge(60 * 60 * 24);
cookie.setPath("/");
if ("https".equalsIgnoreCase(request.getScheme())) {
    cookie.setSecure(true);
}
// Add SameSite attribute (depending on your Jakarta version)
cookie.setAttribute("SameSite", "Lax"); // or "Strict" for more security

// For older Jakarta/Servlet versions, use header
response.setHeader("Set-Cookie", response.getHeader("Set-Cookie") + "; SameSite=Lax");

Similar updates would be needed in the clearUserIdCookie method as well. This would strengthen the CSRF protection mentioned in the earlier comment.

✏️ Learnings added
Learnt from: drtechie
PR: PSMRI/Identity-API#87
File: src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java:23-84
Timestamp: 2025-04-10T05:08:55.382Z
Learning: SameSite cookie attribute should be set to enhance CSRF protection in the Identity-API project. This can be configured using cookie.setAttribute("SameSite", "Strict") or cookie.setAttribute("SameSite", "Lax") depending on requirements.

Learnt from: drtechie
PR: PSMRI/Identity-API#87
File: src/main/java/com/iemr/common/identity/utils/JwtUserIdValidationFilter.java:23-84
Timestamp: 2025-04-10T05:08:55.382Z
Learning: In the Identity-API project, SameSite cookie attribute should be set to enhance CSRF protection. This can be configured using cookie.setAttribute("SameSite", "Strict") or cookie.setAttribute("SameSite", "Lax") depending on requirements. For older Jakarta/Servlet versions, it may require using response.setHeader("Set-Cookie", response.getHeader("Set-Cookie") + "; SameSite=Lax").

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +43 to +49
public Claims validateToken(String token) {
try {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
} catch (Exception e) {
return null; // Handle token parsing/validation errors
}
}
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Improve token validation error handling

The current implementation swallows all exceptions and returns null, which can lead to null pointer exceptions and makes debugging difficult.

Consider:

  1. Logging validation errors
  2. Using more specific exception handling
  3. Potentially differentiating between different validation failure reasons
public Claims validateToken(String token) {
    try {
        return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
    } catch (Exception e) {
-        return null; // Handle token parsing/validation errors
+        // Log the exception
+        logger.error("JWT validation error: {}", e.getMessage());
+        return null; // Handle token parsing/validation errors
    }
}

For more detailed error handling:

public Claims validateToken(String token) {
    try {
        return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
    } catch (ExpiredJwtException e) {
        logger.warn("JWT token expired: {}", e.getMessage());
        return null;
    } catch (MalformedJwtException e) {
        logger.error("Invalid JWT token: {}", e.getMessage());
        return null;
    } catch (UnsupportedJwtException e) {
        logger.error("Unsupported JWT token: {}", e.getMessage());
        return null;
    } catch (Exception e) {
        logger.error("JWT validation error: {}", e.getMessage());
        return null;
    }
}

Comment on lines +1 to +85
package com.iemr.common.identity.utils;

import com.iemr.common.identity.utils.exception.IEMRException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.security.Key;
import java.util.Date;
import java.util.function.Function;

@Component
public class JwtUtil {

@Value("${jwt.secret}")
private String SECRET_KEY;

private static final long EXPIRATION_TIME = 24L * 60 * 60 * 1000; // 1 day in milliseconds

// Generate a key using the secret
private Key getSigningKey() {
if (SECRET_KEY == null || SECRET_KEY.isEmpty()) {
throw new IllegalStateException("JWT secret key is not set in application.properties");
}
return Keys.hmacShaKeyFor(SECRET_KEY.getBytes());
}

// Generate JWT Token
public String generateToken(String username, String userId) {
Date now = new Date();
Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME);

// Include the userId in the JWT claims
return Jwts.builder().setSubject(username).claim("userId", userId) // Add userId as a claim
.setIssuedAt(now).setExpiration(expiryDate).signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}

// Validate and parse JWT Token
public Claims validateToken(String token) {
try {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
} catch (Exception e) {
return null; // Handle token parsing/validation errors
}
}


public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}

public Integer extractUserId(String jwtToken) throws IEMRException {
try {
// Validate JWT token and extract claims
Claims claims = validateToken(jwtToken);

if (claims == null) {
throw new IEMRException("Invalid JWT token.");
}

String userId = claims.get("userId", String.class);

return Integer.parseInt(userId);

} catch (Exception e) {
throw new IEMRException("Validation error: " + e.getMessage(), e);
}


}


public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}

private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
}
} No newline at end of file
Copy link

Choose a reason for hiding this comment

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

πŸ’‘ Verification agent

🧩 Analysis chain

Add unit tests for JWT token functionality

This is a critical security component that requires thorough testing to ensure correct behavior.

Please verify if there are unit tests covering:

  1. Token generation with valid inputs
  2. Token validation with valid/invalid tokens
  3. Claim extraction with various scenarios
  4. Error handling for malformed tokens

🏁 Script executed:

#!/bin/bash
# Search for test files related to JwtUtil
echo "Searching for test files related to JwtUtil..."
find src/test -name "*JwtUtil*Test.java" -o -name "Test*JwtUtil*.java" -o -name "*JwtTest*.java"

# Search for any tests that might use JwtUtil
echo "Searching for tests that might test JWT functionality..."
grep -r "JwtUtil" --include="*.java" src/test 2>/dev/null || echo "No references found"

Length of output: 419


Action Required: Add Comprehensive Unit Tests for JWT Functionality

It appears that the JwtUtil class is not currently covered by any unit tests. Please add tests that validate the following scenarios:

  • Token Generation: Verify that tokens are generated correctly when provided with valid username and userId inputs.
  • Token Validation: Ensure that valid tokens are correctly parsed, while invalid, expired, or malformed tokens result in appropriate error handling.
  • Claim Extraction: Confirm that claims (especially the username and userId) are accurately extracted from the token.
  • Error Handling: Test that errors (such as a missing or empty secret key) are properly handled and that the corresponding exceptions or error messages are produced.

Consider creating a new file (e.g., src/test/java/com/iemr/common/identity/utils/JwtUtilTest.java) to house these tests.

Comment on lines +82 to +84
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
}
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Prevent duplicate code and add error handling in extractAllClaims

The extractAllClaims method duplicates code from validateToken without the same error handling.

private Claims extractAllClaims(String token) {
-    return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
+    Claims claims = validateToken(token);
+    if (claims == null) {
+        throw new IllegalArgumentException("Invalid token");
+    }
+    return claims;
}

This approach ensures consistent token validation behavior across the application and proper error handling.

πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
}
private Claims extractAllClaims(String token) {
- return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody();
+ Claims claims = validateToken(token);
+ if (claims == null) {
+ throw new IllegalArgumentException("Invalid token");
+ }
+ return claims;
}

@drtechie drtechie requested a review from ravishanigarapu April 5, 2025 09:58
Copy link
Member

Choose a reason for hiding this comment

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

@kevalkanp1011 are all these attributes required for JWT checks?

Copy link
Author

Choose a reason for hiding this comment

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

not all but username, password, userid are required. i followed similar implementation available in other repositories

@drtechie
Copy link
Member

@ravishanigarapu can you check this PR?

Copy link
Contributor

@ravishanigarapu ravishanigarapu left a comment

Choose a reason for hiding this comment

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

@kevalkanp1011 Please Add jwtToken as header in Common API where we are calling identity API's
CC : @drtechie

@kevalkanp1011
Copy link
Author

jwtToken is already configured through middlewares in Common-API. @ravishanigarapu . please review asap so i can raise a new PR for cors config

@kevalkanp1011
Copy link
Author

@drtechie

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
4.4% Duplication on New Code (required ≀ 3%)

See analysis details on SonarQube Cloud

@vishwab1 vishwab1 closed this Jun 24, 2025
@coderabbitai coderabbitai bot mentioned this pull request Jul 30, 2025
10 tasks
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.

4 participants