-
Notifications
You must be signed in to change notification settings - Fork 49
jwt api implementation #138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis pull request introduces changes to dependency management in Changes
Possibly related PRs
Suggested reviewers
Poem
π Recent review detailsConfiguration used: CodeRabbit UI π Files selected for processing (6)
π§ Files skipped from review as they are similar to previous changes (6)
β° Context from checks skipped due to timeout of 90000ms (4)
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? πͺ§ TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
π§Ή Outside diff range and nitpick comments (19)
src/main/environment/common_test.properties (2)
Line range hint
1-169: Enhance security of sensitive configurationsThe properties file contains multiple sensitive configurations in plaintext. Consider implementing the following security improvements:
- Encrypt all sensitive values (passwords, API keys, secrets) similar to how
encDbUserNameandencDbPassare encrypted- Move sensitive configurations to a secure vault solution (e.g., HashiCorp Vault, AWS Secrets Manager)
- Use environment variables for sensitive values instead of hardcoding them in properties files
Line range hint
1-169: Improve configuration management structureThe properties file contains a mix of different types of configurations. Consider the following improvements:
- Split configurations into logical groups (e.g.,
application-db.properties,application-security.properties)- Use Spring Cloud Config Server for centralized configuration management
- Document the purpose and format of each configuration property
- Remove or update hardcoded URLs to use environment-specific values
src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java (1)
1175-1191: LGTM with minor suggestions for improvement.The implementation looks good with proper error handling and logging. Consider these minor improvements:
public User getUserById(Long userId) throws IEMRException { + if (userId == null) { + throw new IEMRException("User ID cannot be null"); + } + try { // Fetch user from custom repository by userId User user = iEMRUserRepositoryCustom.findByUserID(userId); // Check if user is found if (user == null) { throw new IEMRException("User not found with ID: " + userId); } return user; } catch (Exception e) { // Log and throw custom exception in case of errors logger.error("Error fetching user with ID: " + userId, e); - throw new IEMRException("Error fetching user with ID: " + userId, e); + throw new IEMRException("Failed to fetch user: " + e.getMessage(), e); } }The changes add:
- Null check for userId parameter
- More specific error message that includes the root cause
src/main/environment/common_dev.properties (4)
Line range hint
5-19: Consolidate and secure database configurationsThere appear to be duplicate database configurations with credentials exposed in plaintext. This poses several concerns:
- Security risk from exposed credentials
- Maintenance overhead from redundant configurations
- IP addresses hardcoded in configuration
Recommendations:
- Remove duplicate configurations
- Use environment variables for sensitive data
- Consider using connection pools
- Use DNS names instead of IP addresses
- Implement a secure vault solution
Example implementation:
# Primary Database spring.datasource.url=${PRIMARY_DB_URL} spring.datasource.username=${PRIMARY_DB_USER} spring.datasource.password=${PRIMARY_DB_PASSWORD} spring.datasource.driver-class-name=com.mysql.jdbc.Driver # Secondary Database secondary.datasource.url=${SECONDARY_DB_URL} secondary.datasource.username=${SECONDARY_DB_USER} secondary.datasource.password=${SECONDARY_DB_PASSWORD} secondary.datasource.driver-class-name=com.mysql.jdbc.Driver
Line range hint
35-42: Secure SMS configuration credentialsSMS service credentials are exposed in plaintext. This could lead to unauthorized access to SMS services.
Recommendation:
send-sms=true sendSMSUrl=${SMS_SERVICE_URL} source-address=AIDSHL sms-username=${SMS_USERNAME} sms-password=${SMS_PASSWORD} send-message-url=${SMS_SEND_URL}
Line range hint
45-52: Secure email configurationEmail credentials are exposed in plaintext, which poses a security risk.
Recommendation:
spring.mail.host=${SMTP_HOST} spring.mail.port=${SMTP_PORT} spring.mail.username=${SMTP_USERNAME} spring.mail.password=${SMTP_PASSWORD} spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true
Line range hint
1-168: General security and configuration improvements neededSeveral overall improvements are recommended for this configuration file:
Organization:
- Group related properties together
- Add clear section headers
- Consider splitting into domain-specific files
Security:
- Remove all hardcoded credentials
- Remove IP addresses
- Use environment variables or secure vaults
- Implement encryption for sensitive values
Documentation:
- Add comments explaining non-obvious configurations
- Document required environment variables
- Include validation requirements for values
Would you like assistance in restructuring this configuration file with these improvements?
src/main/java/com/iemr/common/utils/CookieUtil.java (2)
1-14: Add security-related documentation to the class.Consider adding class-level documentation that describes:
- The security implications of cookie-based JWT storage
- The intended usage context (e.g., HTTPS-only environments)
- Any specific security measures implemented
@Service +/** + * Utility class for secure handling of JWT tokens in cookies. + * This class implements security best practices including: + * - HttpOnly cookies to prevent XSS + * - Secure flag to ensure HTTPS-only transmission + * - Path-scoped cookies + * + * Note: This utility should only be used in HTTPS environments. + */ public class CookieUtil {
1-46: Consider adding integration tests and security documentation.As this class handles security-critical JWT tokens:
- Add integration tests covering various scenarios (valid/invalid tokens, cookie presence/absence)
- Document integration with other JWT-related components
- Consider adding logging for security events
Would you like me to help create:
- Integration test templates?
- Security documentation template?
- Logging implementation?
src/main/java/com/iemr/common/utils/JwtUtil.java (3)
20-21: Consider securing theSECRET_KEYhandlingStoring the
SECRET_KEYas a plainStringmay pose security risks. Consider using achar[]or aSecretKeySpecobject to minimize the exposure of sensitive data in memory.
28-28: Update the exception message for accuracyThe error message mentions "application.properties", but the application may use different properties files. To avoid confusion, consider making the message more generic.
Apply this change:
-throw new IllegalStateException("JWT secret key is not set in application.properties"); +throw new IllegalStateException("JWT secret key is not properly configured");
23-23: MakeEXPIRATION_TIMEconfigurableCurrently,
EXPIRATION_TIMEis hardcoded. Consider externalizing it to application properties to allow flexibility for different environments.Apply this change:
-private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 1 day in milliseconds +@Value("${jwt.expiration_time}") +private long EXPIRATION_TIME;pom.xml (1)
195-201: Avoid specifying versions for Spring-managed dependenciesExplicitly specifying versions for
jacksondependencies may lead to conflicts with the Spring Boot BOM. It's better to rely on the versions managed by the Spring Boot parent.Apply this change:
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> - <version>2.17.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> - <version>2.17.0</version> </dependency>src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java (5)
28-29: InjectIEMRAdminUserServiceImplvia constructor for consistencyYou're mixing field injection and constructor injection. For better consistency and testability, consider injecting
IEMRAdminUserServiceImplthrough the constructor along with the other dependencies.Apply this diff to refactor the injection:
public class JwtAuthenticationUtil { private final CookieUtil cookieUtil; private final JwtUtil jwtUtil; + private final IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl; - @Autowired - private IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl; public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil, IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl) { this.cookieUtil = cookieUtil; this.jwtUtil = jwtUtil; + this.iEMRAdminUserServiceImpl = iEMRAdminUserServiceImpl; }Also applies to: 31-34
31-34: Annotate the constructor with@Autowiredfor clarityWhile Spring can infer the constructor to use when there's only one, explicitly annotating the constructor with
@Autowiredimproves readability and makes the dependency injection clear.Apply this diff to annotate the constructor:
+ @Autowired public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil, IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl) { this.cookieUtil = cookieUtil; this.jwtUtil = jwtUtil; this.iEMRAdminUserServiceImpl = iEMRAdminUserServiceImpl; }
52-59: Log authentication failures for security auditingWhile avoiding detailed error messages in responses, it is important to log authentication failures for security auditing purposes. Ensure that all authentication failures are appropriately logged with necessary details.
Example:
if (usernameFromToken == null || usernameFromToken.isEmpty()) { logger.warn("JWT validation failed: username is missing"); return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized access."); }
36-60: Add unit tests forvalidateJwtTokenmethodThe
validateJwtTokenmethod is critical for authentication. Adding unit tests can help ensure its reliability and security.Would you like assistance in generating unit tests for this method?
62-90: Add unit tests forvalidateUserIdAndJwtTokenmethodTesting the
validateUserIdAndJwtTokenmethod will help catch potential issues and verify that the logic behaves as expected under various scenarios.Would you like assistance in creating unit tests for this method?
src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java (1)
86-89: Catch specific exceptions instead of the genericExceptionCatching broad exceptions like
Exceptioncan make debugging difficult and may mask underlying issues. Consider catching more specific exceptions related to JWT validation.For example, if
validateUserIdAndJwtTokenthrows a specific exception, you can modify the catch block:- } catch (Exception e) { + } catch (JwtValidationException e) {Ensure you import the specific exception class and handle any additional required changes.
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
π Files selected for processing (12)
pom.xml(6 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/service/users/IEMRAdminUserServiceImpl.java(1 hunks)src/main/java/com/iemr/common/utils/CookieUtil.java(1 hunks)src/main/java/com/iemr/common/utils/FilterConfig.java(1 hunks)src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java(1 hunks)src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java(1 hunks)src/main/java/com/iemr/common/utils/JwtUtil.java(1 hunks)
π Additional comments (10)
src/main/environment/common_test.properties (1)
169-169: Verify JWT configuration across environments
The AI summary indicates similar JWT secret entries were added to multiple property files. Let's verify this for consistency.
β Verification successful
JWT secret placeholder consistently configured across all environments β
The JWT secret configuration has been verified across all environment property files:
- All environment files (dev, test, ci, uat, example) contain the JWT secret configuration
- The placeholder
<Enter_Your_Secret_Key>is consistently used across all environments - No environment-specific secrets are committed to the codebase, following security best practices
π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check JWT secret configuration across different property files
# Expected: All environment property files should have the JWT secret configured
echo "Checking JWT secret configuration across environment files..."
rg -l "jwt.secret" "src/main/environment/"
Length of output: 392
Script:
#!/bin/bash
# Let's check the actual values of jwt.secret across these files
echo "Checking JWT secret values across environment files..."
rg "jwt\.secret=" "src/main/environment/"
Length of output: 554
src/main/environment/common_uat.properties (1)
Line range hint 1-141: Review security configuration practices
Several security concerns in the configuration:
- Multiple sensitive credentials are stored in plain text
- Some service URLs use HTTP instead of HTTPS (e.g.,
km-base-url,cti-logger_base_url) - IP addresses and ports are hardcoded
Recommendations:
- Use a secure configuration management system (e.g., HashiCorp Vault, AWS Secrets Manager)
- Enforce HTTPS for all external communications
- Make service discovery configuration driven
Let's verify the use of insecure URLs:
src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java (1)
1175-1191: Verify JWT integration.
Since this method is part of JWT API implementation, let's verify its integration with JWT-related components.
β Verification successful
Let me check the content of these JWT files to see if and how they use the getUserById method.
JWT integration is properly implemented
The verification shows that getUserById is correctly integrated with JWT authentication:
- The method is used in
JwtAuthenticationUtilto validate user existence during token validation - It's properly autowired via
@Autowired private IEMRAdminUserServiceImpl - The implementation follows security best practices by validating both the token and user existence
π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Find JWT-related files that might use getUserById method
# Test: Look for JWT authentication/validation files that may use this method
# Search for JWT-related files
echo "Searching for JWT-related files..."
rg -l "JWT|JsonWebToken" --type java
# Search for references to getUserById
echo -e "\nSearching for getUserById usage..."
ast-grep --pattern 'getUserById($$$)'
Length of output: 473
Script:
#!/bin/bash
# Check content of JWT-related files for any references to getUserById
echo "Checking JwtUserIdValidationFilter.java..."
rg -A 5 -B 5 "getUserById|IEMRAdminUserServiceImpl" src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java
echo -e "\nChecking JwtUtil.java..."
rg -A 5 -B 5 "getUserById|IEMRAdminUserServiceImpl" src/main/java/com/iemr/common/utils/JwtUtil.java
echo -e "\nChecking JwtAuthenticationUtil.java..."
rg -A 5 -B 5 "getUserById|IEMRAdminUserServiceImpl" src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java
# Also check for any autowiring or dependency injection of the service
echo -e "\nChecking for service injection..."
rg "IEMRAdminUserService|IEMRAdminUserServiceImpl" src/main/java/com/iemr/common/utils/Jwt.*
Length of output: 2089
src/main/environment/common_dev.properties (1)
168-168: Verify JWT configuration across environments
Let's ensure consistent JWT configuration across different environments and proper implementation in the code.
β Verification successful
Let me gather more information about the JWT implementation to ensure proper configuration and usage.
JWT configuration is properly implemented and consistent
The verification shows:
- JWT secret is consistently configured across all environment files (dev, test, UAT, CI)
- JwtUtil properly loads the secret from properties using
@Value("${jwt.secret}")annotation - There are no hardcoded secrets in the implementation
- Proper validation is in place to check if the secret is set
- JWT implementation is well-structured with separate classes for util, authentication, and filtering
π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check JWT configuration across environment files
echo "Checking JWT configuration across environments..."
rg "jwt.secret" src/main/environment/
# Look for JWT token generation and validation implementation
echo "Checking JWT implementation..."
rg -l "jwt" src/main/java/
ast-grep --pattern 'class $_ implements $_ {
$$$
@Autowired
private $_ jwtTokenUtil;
$$$
}'
Length of output: 973
Script:
#!/bin/bash
# Check the actual implementation of JWT token generation and validation
echo "Checking JWT token generation and validation..."
ast-grep --pattern 'class JwtUtil {
$$$
}'
# Check for any hardcoded JWT secrets in the code
echo "Checking for hardcoded JWT secrets..."
rg -i "secret" src/main/java/com/iemr/common/utils/JwtUtil.java
# Check FilterConfig implementation
echo "Checking JWT filter configuration..."
ast-grep --pattern 'class FilterConfig {
$$$
}'
Length of output: 783
src/main/java/com/iemr/common/utils/FilterConfig.java (3)
1-6: LGTM!
Package structure and imports are appropriate and minimal.
7-8: Verify filter configuration order and potential conflicts.
The configuration looks correct, but we should ensure this filter's execution order doesn't conflict with other security filters.
β Verification successful
Let me check the actual filter configuration implementation to make a proper assessment.
No filter configuration conflicts found
The implementation shows a single JWT validation filter with:
- Clear registration using Spring's
FilterRegistrationBean - Global URL pattern ("/*")
- No conflicting security configurations or other filter definitions in the codebase
π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for other filter configurations and security setup
# Look for other filter configurations and security-related beans
rg -l "FilterRegistrationBean|WebSecurityConfigurerAdapter|SecurityFilterChain"
# Check for security configuration files
fd -e java -e xml "Security|WebConfig|FilterConfig"
Length of output: 549
Script:
#!/bin/bash
# Check the actual implementation of FilterConfig
ast-grep --pattern 'class FilterConfig {
$$$
}'
# Also check for any filter bean definitions
rg -A 10 "FilterRegistrationBean|@Bean.*Filter" src/main/java/com/iemr/common/utils/FilterConfig.java
Length of output: 849
11-16: π οΈ Refactor suggestion
Enhance error handling and logging for security events.
As this is a security-critical component, consider adding:
- Proper error handling strategy
- Security event logging
- Metrics for failed authentication attempts
Consider injecting a logger and implementing proper error handling:
@Bean
public FilterRegistrationBean<JwtUserIdValidationFilter> jwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) {
FilterRegistrationBean<JwtUserIdValidationFilter> registrationBean = new FilterRegistrationBean<>();
- registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil));
+ JwtUserIdValidationFilter filter = new JwtUserIdValidationFilter(jwtAuthenticationUtil);
+ filter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler());
+ registrationBean.setFilter(filter);
registrationBean.addUrlPatterns("/*");
return registrationBean;
}pom.xml (1)
450-481: Verify compatibility of Jersey and javax.ws.rs dependencies
Including both javax.ws.rs and Jersey dependencies of different versions might cause compatibility issues due to package namespace changes. Ensure that all dependencies are aligned with the Jakarta EE specifications used by your version of Spring Boot.
src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java (2)
59-59: Avoid returning sensitive information in response bodies
Returning the username in the response body can expose sensitive user information. Consider returning a generic success message or omitting the body content for a 200 OK response.
[security_issue]
Apply this diff to prevent exposure of sensitive data:
- return ResponseEntity.ok(usernameFromToken);
+ return ResponseEntity.ok("JWT token is valid.");Alternatively, you can return an empty body:
- return ResponseEntity.ok(usernameFromToken);
+ return ResponseEntity.ok().build();39-42: Standardize error responses and avoid detailed error messages
Providing detailed error messages can give potential attackers information about the application's internals. It's better to standardize error responses without specifying exact reasons.
[security_issue]
Consider updating the error responses:
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
- .body("Error 401: Unauthorized - JWT Token is not set!");
+ .body("Unauthorized access.");
...
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
- .body("Error 401: Unauthorized - Invalid JWT Token!");
+ .body("Unauthorized access.");
...
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
- .body("Error 401: Unauthorized - Username is missing!");
+ .body("Unauthorized access.");Also applies to: 48-50, 54-56
|
|
||
| fileBasePath =<Enter your required basepath here>/Doc | ||
|
|
||
| jwt.secret=<Enter_Your_Secret_Key> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Secure the JWT secret configuration
The JWT secret is a critical security component that should be properly secured. Consider the following recommendations:
- Use a strong, randomly generated secret key
- Ensure the secret is at least 256 bits (32 characters) long
- Consider encrypting the secret similar to how database credentials are encrypted (see
encDbUserName)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Thank you for addressing the JWT secret configuration. The placeholder approach is consistent with the file's security practices.
βοΈ Learnings added
Learnt from: indraniBan
PR: PSMRI/Common-API#138
File: src/main/environment/common_test.properties:0-0
Timestamp: 2025-02-03T12:41:44.791Z
Learning: In Common-API, JWT secrets should be configured using placeholders (e.g., `<Enter_Your_Secret_Key>`) in properties files, similar to other sensitive credentials, to prevent accidental commit of actual secrets.
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.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
|
|
||
| fileBasePath =<Enter your required basepath here>/Doc | ||
|
|
||
| jwt.secret=<Enter_Your_Secret_Key> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure secure JWT secret key management
The JWT secret configuration uses a placeholder value. For security:
- Use a strong, randomly generated secret key (at least 256 bits)
- Consider using environment variables or a secure vault instead of properties files
- Ensure the secret differs across environments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan I notice that while the CI environment correctly uses an environment variable (@env.JWT_SECRET_KEY@), the JWT secret is still empty in other environment properties files (dev, test, UAT). For security:
- Consider using environment variables in all environments like:
jwt.secret=@env.JWT_SECRET_KEY@- Ensure each environment has its JWT secret properly configured through environment variables.
Would you like me to create a follow-up issue to track this security enhancement?
π Analysis chain
π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check the current JWT secret configuration in all property files
echo "Checking JWT secret configuration in property files..."
rg "jwt.secret=" src/main/environment/
Length of output: 456
βοΈ Learnings added
Learnt from: indraniBan
PR: PSMRI/Common-API#138
File: src/main/environment/common_uat.properties:0-0
Timestamp: 2025-02-03T12:41:58.823Z
Learning: In the Common-API project, JWT secret configuration should use environment variables (e.g., `jwt.secret=@env.JWT_SECRET_KEY@`) across all environments for better security.
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.
| spring.main.allow-circular-references=true | ||
|
|
||
| fileBasePath =<Enter your required basepath here>/Doc | ||
| jwt.secret=<Enter_Your_Secret_Key> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Secure the JWT secret using environment variables or a secure vault
The JWT secret is a critical security component and should not be stored in the properties file. Consider:
- Using environment variables
- Implementing a secure vault solution (e.g., HashiCorp Vault, AWS Secrets Manager)
Example implementation using environment variables:
-jwt.secret=<Enter_Your_Secret_Key>
+jwt.secret=${JWT_SECRET}π 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.
| jwt.secret=<Enter_Your_Secret_Key> | |
| jwt.secret=${JWT_SECRET} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Thanks for implementing this security improvement!
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
| @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 | ||
| return registrationBean; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ Codebase verification
Consider refining JWT filter configuration for better security.
Based on the codebase analysis:
- The application has authentication endpoints and Swagger configuration (SwaggerConfig.java), which should be excluded from JWT validation.
- No explicit security configuration (SecurityConfig) was found, making filter order even more critical.
- The application uses actuator endpoints (as seen in logging configuration), which should remain accessible.
@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.addUrlPatterns("/api/*", "/v1/*"); // Apply only to API endpoints
+ registrationBean.setOrder(1); // Explicit order
+ // Exclude authentication, Swagger, and monitoring endpoints
+ registrationBean.addInitParameter("excludePatterns",
+ "/login/**, /auth/**, /swagger-ui/**, /v3/api-docs/**, /actuator/**");
return registrationBean;
}π Analysis chain
Consider refining filter configuration for security and reliability.
While the basic setup is correct, there are several important considerations:
-
The current configuration applies JWT validation to all endpoints ("/*"), which might not be desirable for:
- Health check endpoints
- Public API endpoints
- Swagger/API documentation
- Authentication endpoints themselves
-
The filter order is not specified, which is crucial when working with security filters.
Consider these improvements:
@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.addUrlPatterns("/api/*"); // Apply only to API endpoints
+ registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 1); // Set after security filters
+ registrationBean.addInitParameter("excludePatterns", "/api/auth/**, /actuator/**, /swagger-ui/**, /v3/api-docs/**");
return registrationBean;
}π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for endpoints that might need exclusion
# Look for authentication endpoints
rg -l "login|authenticate|/auth" --type java
# Look for actuator/monitoring configuration
fd -e properties -e yaml -e xml | xargs rg "management.endpoints|actuator"
Length of output: 1961
Script:
#!/bin/bash
# Let's check for authentication endpoints and their patterns
rg -A 5 "@(GetMapping|PostMapping|RequestMapping).*/auth" --type java
# Check if there are any existing security configurations
rg -l "SecurityConfig|WebSecurityConfigurerAdapter|SecurityFilterChain" --type java
# Look for actuator configuration in properties files
fd "application" -e properties -e yml | xargs cat
# Check for Swagger/OpenAPI configurations
rg -l "OpenAPI|Swagger|springdoc|springfox" --type java
Length of output: 10645
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Understood, I'll retract my suggestion. The current filter configuration will be maintained as is.
| public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) { | ||
| Cookie[] cookies = request.getCookies(); | ||
| if (cookies != null) { | ||
| for (Cookie cookie : cookies) { | ||
| if (cookieName.equals(cookie.getName())) { | ||
| return Optional.of(cookie.getValue()); | ||
| } | ||
| } | ||
| } | ||
| return Optional.empty(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add input validation and null checks.
The method should validate the cookieName parameter and handle the case when it's null.
- public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) {
+ public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) {
+ if (request == null || cookieName == null || cookieName.trim().isEmpty()) {
+ return Optional.empty();
+ }
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {π 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.
| public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) { | |
| Cookie[] cookies = request.getCookies(); | |
| if (cookies != null) { | |
| for (Cookie cookie : cookies) { | |
| if (cookieName.equals(cookie.getName())) { | |
| return Optional.of(cookie.getValue()); | |
| } | |
| } | |
| } | |
| return Optional.empty(); | |
| } | |
| public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) { | |
| if (request == null || cookieName == null || cookieName.trim().isEmpty()) { | |
| return Optional.empty(); | |
| } | |
| Cookie[] cookies = request.getCookies(); | |
| if (cookies != null) { | |
| for (Cookie cookie : cookies) { | |
| if (cookieName.equals(cookie.getName())) { | |
| return Optional.of(cookie.getValue()); | |
| } | |
| } | |
| } | |
| return Optional.empty(); | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Understood, I'll retract the suggestion. Let me know if you need any other assistance!
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
| @Autowired | ||
| private final CookieUtil cookieUtil; | ||
| @Autowired | ||
| private final JwtUtil jwtUtil; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove @Autowired annotations and use constructor injection for final fields
The fields cookieUtil and jwtUtil are declared as final and annotated with @Autowired. Spring cannot inject final fields using field injection. Since you're already providing these dependencies through the constructor, you should remove the @Autowired annotations from the fields to avoid injection issues.
Apply this diff to fix the issue:
- @Autowired
- private final CookieUtil cookieUtil;
- @Autowired
- private final JwtUtil jwtUtil;
+ private final CookieUtil cookieUtil;
+ private final JwtUtil jwtUtil;π 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.
| @Autowired | |
| private final CookieUtil cookieUtil; | |
| @Autowired | |
| private final JwtUtil jwtUtil; | |
| private final CookieUtil cookieUtil; | |
| private final JwtUtil jwtUtil; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Thanks for fixing that! π
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
| } catch (Exception e) { | ||
| logger.error("Validation failed: " + e.getMessage(), e); | ||
| throw new IEMRException("Validation error: " + e.getMessage(), e); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Catch specific exceptions instead of the generic Exception
Catching the generic Exception can obscure the source of errors and may unintentionally catch exceptions that should be handled elsewhere. It's better to catch specific exceptions that you expect.
Identify the specific exceptions thrown within the try block and update the catch clause accordingly. For example:
- } catch (Exception e) {
+ } catch (IEMRException | JwtException | NumberFormatException e) {Ensure that you've imported any additional exception classes needed.
Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Understood, I'll move on from this suggestion.
βοΈ Learnings added
Learnt from: indraniBan
PR: PSMRI/Common-API#138
File: src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java:0-0
Timestamp: 2025-02-03T12:42:38.039Z
Learning: In the JwtAuthenticationUtil class, catching a generic Exception in the validateUserIdAndJwtToken method is acceptable as per the team's preference.
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.
| // Retrieve JWT token from cookies | ||
| String jwtTokenFromCookie = getJwtTokenFromCookies(request); | ||
| logger.info("JWT token from cookie: " + jwtTokenFromCookie); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid logging sensitive information like JWT tokens
Logging JWT tokens can expose sensitive information and pose security risks. It's recommended to avoid logging the actual token values.
Apply this diff to prevent logging the token value:
- logger.info("JWT token from cookie: " + jwtTokenFromCookie);
+ logger.info("JWT token from cookie is present: " + (jwtTokenFromCookie != null));Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rate Limit Exceeded
@indraniBan have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 19 seconds before sending another message.
|
|
||
| // Log headers for debugging | ||
| String jwtTokenFromHeader = request.getHeader("Jwttoken"); | ||
| logger.info("JWT token from header: " + jwtTokenFromHeader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid logging sensitive information like JWT tokens
Logging JWT tokens can expose sensitive information and pose security risks. It's recommended to avoid logging the actual token values.
Apply this diff to prevent logging the token value:
- logger.info("JWT token from header: " + jwtTokenFromHeader);
+ logger.info("JWT token from header is present: " + (jwtTokenFromHeader != null));π 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.
| logger.info("JWT token from header: " + jwtTokenFromHeader); | |
| logger.info("JWT token from header is present: " + (jwtTokenFromHeader != null)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rate Limit Exceeded
@indraniBan have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 2 seconds before sending another message.
| } | ||
| } catch (Exception e) { | ||
| logger.error("Authorization error: ", e); | ||
| response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid exposing exception messages in HTTP responses
Including exception messages in HTTP responses can leak sensitive information and aid potential attackers. It's safer to return a generic error message.
Apply this diff to use a generic error message:
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage());
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error");π 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.
| response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); | |
| response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Understood, I'll respect your decision to keep the detailed error messages.
π° nods understandingly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
π§Ή Outside diff range and nitpick comments (2)
pom.xml (2)
175-177: Consider removing commented-out dependenciesThe commented-out Jackson dependencies should either be removed or documented with a reason for keeping them as comments. This helps maintain clean and maintainable configuration.
Also applies to: 184-185
Line range hint
1-644: Architecture recommendations for JWT and Redis implementationGiven the addition of Redis for session management and JWT for authentication:
- Ensure proper session configuration is added to application properties
- Consider implementing rate limiting using Redis
- Plan for JWT token rotation and revocation strategy
- Consider implementing Redis cluster configuration for high availability
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
π Files selected for processing (1)
pom.xml(6 hunks)
π Additional comments (5)
pom.xml (5)
69-72: LGTM: Dependency formatting improvement
The formatting of the logback-ecs-encoder dependency has been improved for better readability.
193-202: Verify compatibility between Jackson versions
The Jackson core and annotations dependencies are set to version 2.17.0, which is newer than other Spring dependencies. Ensure this doesn't cause compatibility issues with Spring Boot 3.2.2.
506-506: Major version bump requires documentation
The finalName has been updated from commonapi-v1.0 to commonapi-v3.0.0, which indicates a major version change. This should be documented in the changelog or release notes.
Line range hint 571-576: Review property file concatenation security
The concatenation of property files during the build process should be reviewed to ensure sensitive information (like JWT secrets) is properly handled.
482-501: Verify JWT dependency security
The JWT dependencies (jjwt-api, jjwt-impl, jjwt-jackson) are using version 0.11.5. While this is a stable version, ensure it doesn't have known security vulnerabilities.
| <dependency> | ||
| <groupId>javax.ws.rs</groupId> | ||
| <artifactId>javax.ws.rs-api</artifactId> | ||
| <version>2.1.1</version> | ||
| </dependency> | ||
|
|
||
| <!-- Jersey Core --> | ||
| <dependency> | ||
| <groupId>org.glassfish.jersey.core</groupId> | ||
| <artifactId>jersey-common</artifactId> | ||
| <version>2.30.1</version> | ||
| </dependency> | ||
| <dependency> | ||
| <groupId>org.glassfish.jersey.core</groupId> | ||
| <artifactId>jersey-server</artifactId> | ||
| <version>2.30.1</version> | ||
| </dependency> | ||
|
|
||
|
|
||
| <!-- Jersey JSON Processing --> | ||
| <dependency> | ||
| <groupId>org.glassfish.jersey.media</groupId> | ||
| <artifactId>jersey-media-json-processing</artifactId> | ||
| <version>2.30.1</version> | ||
| </dependency> | ||
|
|
||
| <!-- JAXB Runtime Implementation --> | ||
| <dependency> | ||
| <groupId>org.glassfish.jaxb</groupId> | ||
| <artifactId>jaxb-runtime</artifactId> | ||
| <version>2.3.1</version> | ||
| </dependency> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π‘ Codebase verification
π οΈ Refactor suggestion
Jersey dependencies need upgrade for Spring Boot 3.x compatibility
The project is using Spring Boot 3.2.2 which requires Jakarta EE, but the current Jersey dependencies (2.30.1) are using the older javax namespace. This is confirmed by:
- Spring Boot version 3.2.2 in the pom.xml
- Presence of Jakarta dependencies (jakarta.xml.bind-api)
- Jersey 2.x dependencies using the older javax.ws.rs namespace
The original review comment is correct. You should upgrade to Jersey 3.x as it's compatible with Jakarta EE and Spring Boot 3.x. Specifically:
- Update jersey-common from 2.30.1 to 3.1.5
- Update jersey-server from 2.30.1 to 3.1.5
- Update jersey-media-json-processing from 2.30.1 to 3.1.5
- Replace javax.ws.rs-api with jakarta.ws.rs-api
π Analysis chain
Review Jersey dependency versions for compatibility
The Jersey dependencies are using version 2.30.1, which might be outdated compared to the project's Spring Boot version (3.2.2). Consider upgrading to a newer version that's compatible with Jakarta EE.
Consider upgrading Jersey dependencies to version 3.x to align with Jakarta EE:
- <version>2.30.1</version>
+ <version>3.1.5</version>The previous command didn't work well, so let's try to gather more context about the project's dependencies and Spring Boot version to make an informed decision about Jersey compatibility.
π Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for potential version conflicts with Jersey dependencies
rg "jersey" | grep -i "version"
Length of output: 29
Script:
#!/bin/bash
# Let's check the Spring Boot version and other relevant dependencies
cat pom.xml | grep -A 1 "<version>"
# Also check for any Jakarta EE dependencies
rg "jakarta" pom.xml
Length of output: 2470
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
π§Ή Outside diff range and nitpick comments (3)
src/main/java/com/iemr/common/model/user/LoginRequestModel.java (2)
28-28: Document the purpose of withCredentials fieldThe newly added
withCredentialsfield appears to be related to JWT cookie authentication, but its purpose and usage are not documented. Consider adding JavaDoc to clarify:
- When this flag should be set
- The implications of true/false values
- Whether it's required or optional
public @Data class LoginRequestModel { private String userName; private String password; private String authKey; private Boolean doLogout; + /** + * Indicates whether credentials should be included in cross-origin requests. + * Used primarily for JWT cookie-based authentication. + */ private Boolean withCredentials;Also applies to: 33-33
33-33: Consider using primitive booleanThe
withCredentialsfield usesBooleanwrapper type which allows null values. Unless null has a specific meaning in your authentication flow, consider using primitivebooleanwith a default value.- private Boolean withCredentials; + private boolean withCredentials = false;src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java (1)
36-36: Use parameterized logging instead of string concatenationFor better performance and to prevent potential logging issues, consider using parameterized logging.
Apply this diff:
- logger.info("JwtUserIdValidationFilter invoked for path: " + path); + logger.info("JwtUserIdValidationFilter invoked for path: {}", path);
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
π Files selected for processing (9)
pom.xml(6 hunks)src/main/environment/common_ci.properties(1 hunks)src/main/java/com/iemr/common/controller/users/IEMRAdminController.java(12 hunks)src/main/java/com/iemr/common/model/user/LoginRequestModel.java(1 hunks)src/main/java/com/iemr/common/utils/CookieUtil.java(1 hunks)src/main/java/com/iemr/common/utils/FilterConfig.java(1 hunks)src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java(1 hunks)src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java(1 hunks)src/main/java/com/iemr/common/utils/JwtUtil.java(1 hunks)
π§ Files skipped from review as they are similar to previous changes (4)
- src/main/environment/common_ci.properties
- src/main/java/com/iemr/common/utils/FilterConfig.java
- src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java
- src/main/java/com/iemr/common/utils/JwtUtil.java
π Additional comments (8)
src/main/java/com/iemr/common/model/user/LoginRequestModel.java (1)
39-44: π οΈ Refactor suggestion
Update custom constructor to handle new field
The custom constructor for Everwell registration doesn't initialize the new withCredentials field. This could lead to inconsistent behavior depending on how the field is used.
Let's check how this constructor is used:
Consider updating the constructor:
public LoginRequestModel(String userName, String password) {
this.userName = userName;
this.password = password;
+ this.withCredentials = false; // Set default value
}src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java (3)
53-53: Avoid logging sensitive information like JWT tokens
Logging the actual JWT token value can expose sensitive information and pose security risks. It's recommended to avoid logging the token value directly.
Apply this diff to prevent logging the token value:
- logger.info("JWT token from header: " + jwtTokenFromHeader);
+ logger.info("JWT token from header is present: " + (jwtTokenFromHeader != null));67-67: Avoid logging sensitive information like JWT tokens
Logging the actual JWT token value can expose sensitive information and pose security risks. It's recommended to avoid logging the token value directly.
Apply this diff to prevent logging the token value:
- logger.info("JWT token from cookie: " + jwtTokenFromCookie);
+ logger.info("JWT token from cookie is present: " + (jwtTokenFromCookie != null));87-87: Avoid exposing exception messages in HTTP responses
Including exception messages in HTTP responses can leak sensitive information and aid potential attackers. It's safer to return a generic error message.
Apply this diff to use a generic error message:
- response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage());
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error");src/main/java/com/iemr/common/utils/CookieUtil.java (3)
15-25: Add input validation and null checks
The method should validate the cookieName parameter and handle cases where it's null or empty to prevent potential errors.
Apply this diff:
public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) {
+ if (request == null || cookieName == null || cookieName.trim().isEmpty()) {
+ return Optional.empty();
+ }
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookieName.equals(cookie.getName())) {
return Optional.of(cookie.getValue());
}
}
}
return Optional.empty();
}27-35: Enhance security and configurability of JWT cookie handling
Several improvements are recommended:
- Validate the
Jwttokenparameter before setting it. - Make cookie properties configurable.
- Add additional security attributes, such as
SameSiteand setting the domain appropriately.
Apply this diff:
+ private static final String JWT_COOKIE_NAME = "Jwttoken";
+ @Value("${jwt.cookie.maxAge:86400}") // 1 day default
+ private int jwtCookieMaxAge;
+
public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response) {
+ if (Jwttoken == null || Jwttoken.trim().isEmpty()) {
+ throw new IllegalArgumentException("JWT token cannot be null or empty");
+ }
// Create a new cookie with the JWT token
- Cookie cookie = new Cookie("Jwttoken", Jwttoken);
+ Cookie cookie = new Cookie(JWT_COOKIE_NAME, Jwttoken);
cookie.setHttpOnly(true); // Prevent JavaScript access for security
cookie.setSecure(true); // Ensure the cookie is sent only over HTTPS
- cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time
+ cookie.setMaxAge(jwtCookieMaxAge);
cookie.setPath("/"); // Make the cookie available for the entire application
+ cookie.setSameSite("Strict"); // Prevent CSRF
response.addCookie(cookie); // Add the cookie to the response
}37-40: Fix potential NullPointerException and maintain consistency with Optional
The method getJwtTokenFromCookie does not check if request.getCookies() is null, which could lead to a NullPointerException. Additionally, consider returning an Optional<String> for consistency with other methods.
Apply this diff:
- public String getJwtTokenFromCookie(HttpServletRequest request) {
- return Arrays.stream(request.getCookies())
- .filter(cookie -> "Jwttoken".equals(cookie.getName()))
- .map(Cookie::getValue).findFirst().orElse(null);
+ public Optional<String> getJwtTokenFromCookie(HttpServletRequest request) {
+ if (request == null || request.getCookies() == null) {
+ return Optional.empty();
+ }
+ return Arrays.stream(request.getCookies())
+ .filter(cookie -> "Jwttoken".equals(cookie.getName()))
+ .map(Cookie::getValue).findFirst();
}pom.xml (1)
444-475: Upgrade Jersey dependencies for Spring Boot 3 compatibility
The project is using Spring Boot 3.2.2, which requires Jakarta EE. The Jersey dependencies currently specified (version 2.30.1) use the older javax namespace and are not compatible with Spring Boot 3. To resolve this, upgrade Jersey dependencies to version 3.x and replace javax.ws.rs-api with jakarta.ws.rs-api.
Apply this diff:
- <dependency>
- <groupId>javax.ws.rs</groupId>
- <artifactId>javax.ws.rs-api</artifactId>
- <version>2.1.1</version>
- </dependency>
+ <dependency>
+ <groupId>jakarta.ws.rs</groupId>
+ <artifactId>jakarta.ws.rs-api</artifactId>
+ <version>3.1.0</version>
+ </dependency>
- <!-- Jersey Core -->
- <dependency>
- <groupId>org.glassfish.jersey.core</groupId>
- <artifactId>jersey-common</artifactId>
- <version>2.30.1</version>
- </dependency>
- <dependency>
- <groupId>org.glassfish.jersey.core</groupId>
- <artifactId>jersey-server</artifactId>
- <version>2.30.1</version>
- </dependency>
+ <!-- Jersey Core -->
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-common</artifactId>
+ <version>3.1.5</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.core</groupId>
+ <artifactId>jersey-server</artifactId>
+ <version>3.1.5</version>
+ </dependency>
- <!-- 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.5</version>
+ </dependency>| // String decryptPassword = aesUtil.decrypt("Piramal12Piramal", | ||
| // m_User.getPassword()); | ||
| // logger.info("decryptPassword : " + m_User.getPassword()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove hardcoded encryption keys from the code
Hardcoded encryption keys like "Piramal12Piramal" should not be present in the codebase, even if commented out. This poses a significant security risk.
Apply this diff to remove the hardcoded key:
- // String decryptPassword = aesUtil.decrypt("Piramal12Piramal", m_User.getPassword());
- // logger.info("decryptPassword : " + m_User.getPassword());There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented lines code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ravishanigarapu I agree, removing those commented lines containing sensitive information is a good security practice.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
| @GetMapping("/get-jwt-token") | ||
| public ResponseEntity<String> getJwtTokenFromCookie(HttpServletRequest httpRequest) { | ||
| // Retrieve the cookie named 'jwtToken' | ||
| Cookie[] cookies = httpRequest.getCookies(); | ||
|
|
||
| if (cookies != null) { | ||
| for (Cookie cookie : cookies) { | ||
| if ("jwtToken".equals(cookie.getName())) { | ||
| String jwtToken = cookie.getValue(); | ||
| // Return the JWT token in the response | ||
| return ResponseEntity.ok(jwtToken); | ||
| } | ||
| } | ||
| } | ||
| // Return 404 if the token is not found in the cookies | ||
| return ResponseEntity.status(HttpStatus.NOT_FOUND).body("JWT token not found"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Inconsistent cookie name and redundant code for retrieving JWT token
The method getJwtTokenFromCookie is manually retrieving the cookie named "jwtToken", whereas elsewhere in the application, the cookie is named "Jwttoken". This inconsistency can lead to issues where the JWT token is not found.
Additionally, consider using the existing CookieUtil's getJwtTokenFromCookie method to avoid code duplication and maintain consistency.
Apply this diff to fix the cookie name and utilize CookieUtil:
- @GetMapping("/get-jwt-token")
- public ResponseEntity<String> getJwtTokenFromCookie(HttpServletRequest httpRequest) {
- // Retrieve the cookie named 'jwtToken'
- Cookie[] cookies = httpRequest.getCookies();
- if (cookies != null) {
- for (Cookie cookie : cookies) {
- if ("jwtToken".equals(cookie.getName())) {
- String jwtToken = cookie.getValue();
- // Return the JWT token in the response
- return ResponseEntity.ok(jwtToken);
- }
- }
- }
- // Return 404 if the token is not found in the cookies
- return ResponseEntity.status(HttpStatus.NOT_FOUND).body("JWT token not found");
- }
+ @GetMapping("/get-jwt-token")
+ public ResponseEntity<String> getJwtTokenFromCookie(HttpServletRequest httpRequest) {
+ Optional<String> jwtTokenOptional = cookieUtil.getJwtTokenFromCookie(httpRequest);
+ if (jwtTokenOptional.isPresent()) {
+ return ResponseEntity.ok(jwtTokenOptional.get());
+ } else {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body("JWT token not found");
+ }
+ }Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rate Limit Exceeded
@indraniBan have exceeded the limit for the number of chat messages per hour. Please wait 1 minutes and 5 seconds before sending another message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
π§Ή Outside diff range and nitpick comments (4)
src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java (1)
1175-1191: Consider adding parameter validation and performance optimizations.The implementation looks good with proper error handling and logging. However, consider these improvements:
- Add parameter validation
- Consider adding caching for frequently accessed users
- Consider adding @transactional annotation if this involves DB operations
+import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Positive; @Service +@Validated public class IEMRAdminUserServiceImpl implements IEMRAdminUserService { // ... existing code ... + @Transactional(readOnly = true) + @Cacheable(value = "users", key = "#userId") public User getUserById( + @NotNull(message = "User ID cannot be null") + @Positive(message = "User ID must be a positive number") Long userId) throws IEMRException { try { // Validate parameter + if (userId == null) { + throw new IEMRException("User ID cannot be null"); + } // Fetch user from custom repository by userId User user = iEMRUserRepositoryCustom.findByUserID(userId); // Check if user is found if (user == null) { throw new IEMRException("User not found with ID: " + userId); } return user; } catch (Exception e) { // Log and throw custom exception in case of errors logger.error("Error fetching user with ID: " + userId, e); throw new IEMRException("Error fetching user with ID: " + userId, e); } }src/main/java/com/iemr/common/controller/users/IEMRAdminController.java (3)
139-139: Consider breaking down the userAuthenticate method.The method handles multiple concerns (authentication, JWT generation, cookie management, user mapping). Consider extracting these into separate methods for better maintainability.
292-296: Add documentation for the isSanjeevani field.Please document the purpose and usage of the
isSanjeevanifield in the role object.
614-616: Add specific error handling for JSON parsing.Consider adding specific error handling for JsonParseException and JsonMappingException to provide better error messages.
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
π Files selected for processing (14)
pom.xml(6 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/controller/users/IEMRAdminController.java(12 hunks)src/main/java/com/iemr/common/model/user/LoginRequestModel.java(1 hunks)src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java(1 hunks)src/main/java/com/iemr/common/utils/CookieUtil.java(1 hunks)src/main/java/com/iemr/common/utils/FilterConfig.java(1 hunks)src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java(1 hunks)src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java(1 hunks)src/main/java/com/iemr/common/utils/JwtUtil.java(1 hunks)
π§ Files skipped from review as they are similar to previous changes (12)
- src/main/environment/common_test.properties
- src/main/environment/common_uat.properties
- src/main/environment/common_example.properties
- src/main/java/com/iemr/common/model/user/LoginRequestModel.java
- src/main/environment/common_ci.properties
- src/main/environment/common_dev.properties
- src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java
- src/main/java/com/iemr/common/utils/CookieUtil.java
- src/main/java/com/iemr/common/utils/FilterConfig.java
- src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java
- src/main/java/com/iemr/common/utils/JwtUtil.java
- pom.xml
π Additional comments (4)
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java (4)
39-40: LGTM: Required JWT dependencies and components are properly integrated.
The new imports and autowired components are correctly structured for JWT implementation.
Also applies to: 66-68, 79-79, 81-81, 90-95
635-637: LGTM: Well-documented API parameter changes.
The new optional parameters are properly documented in the @param annotation.
910-912: Remove hardcoded encryption keys from the code.
Hardcoded encryption keys like "Piramal12Piramal" should not be present in the codebase, even if commented out. This poses a significant security risk.
958-974: Inconsistent cookie name and redundant code for retrieving JWT token.
The method getJwtTokenFromCookie is manually retrieving the cookie named "jwtToken", whereas elsewhere in the application, the cookie is named "Jwttoken". This inconsistency can lead to issues where the JWT token is not found.
Additionally, consider using the existing CookieUtil's getJwtTokenFromCookie method to avoid code duplication and maintain consistency.
| String Jwttoken = jwtUtil.generateToken(m_User.getUserName(), mUser.get(0).getUserID().toString()); | ||
| logger.info("jwt token is:" + Jwttoken); | ||
|
|
||
| // Set Jwttoken in the response cookie | ||
| cookieUtil.addJwtTokenToCookie(Jwttoken, httpResponse); | ||
|
|
||
| resMap.put("Jwttoken", Jwttoken); | ||
| logger.info("response coming from jwt:" + resMap); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Consider adding security headers for JWT cookie.
While the JWT implementation is correct, consider enhancing cookie security by ensuring the cookieUtil.addJwtTokenToCookie method sets these security attributes:
- HttpOnly flag to prevent XSS
- Secure flag for HTTPS
- SameSite attribute to prevent CSRF
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
π§Ή Nitpick comments (3)
src/main/java/com/iemr/common/data/users/User.java (2)
56-56: Add serialVersionUID for Serializable class.When implementing Serializable, it's recommended to define a serialVersionUID to ensure version compatibility during deserialization.
Add this field:
public class User implements Serializable { + private static final long serialVersionUID = 1L;
198-199: Initialize failedAttempt field with a default value.The
failedAttemptfield should be initialized with a default value (typically 0) to avoid null pointer issues.Apply this change:
@JsonIgnore private OutputMapper outPutMapper = new OutputMapper(); @Expose @Column(name = "failed_attempt") - private Integer failedAttempt; + private Integer failedAttempt = 0;Also applies to: 201-203
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java (1)
627-629: Consider using constructor injection for ObjectMapper.While the current implementation works, consider injecting ObjectMapper as a dependency to improve testability and reusability.
Apply this diff:
+ @Autowired + private ObjectMapper objectMapper; @RequestMapping(value = "/getRoleScreenMappingByProviderID", method = RequestMethod.POST) public String getRoleScreenMappingByProviderID(@RequestBody String request) { - ObjectMapper objectMapper = new ObjectMapper(); ServiceRoleScreenMapping serviceRoleScreenMapping = objectMapper.readValue(request, ServiceRoleScreenMapping.class);
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (9)
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/config/RedisConfig.java(1 hunks)src/main/java/com/iemr/common/controller/users/IEMRAdminController.java(13 hunks)src/main/java/com/iemr/common/data/users/User.java(3 hunks)src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java(1 hunks)
π§ Files skipped from review as they are similar to previous changes (5)
- src/main/environment/common_example.properties
- src/main/environment/common_ci.properties
- src/main/environment/common_uat.properties
- src/main/environment/common_test.properties
- src/main/environment/common_dev.properties
π Additional comments (9)
src/main/java/com/iemr/common/config/RedisConfig.java (1)
34-38: LGTM! Good security practice.
The NO_OP configuration prevents Redis CONFIG commands, which is a good security practice in production environments.
src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java (3)
116-116: Handle potential NumberFormatException when parsing userId.
The Long.parseLong() call can throw a NumberFormatException if userId is not a valid number.
92-95: π οΈ Refactor suggestion
Catch specific exceptions instead of generic Exception.
Catching generic Exception can mask underlying issues and make debugging harder.
Apply this change:
- } catch (Exception e) {
+ } catch (NumberFormatException e) {
+ logger.error("Invalid user ID format: " + e.getMessage(), e);
+ throw new IEMRException("Invalid user ID format: " + e.getMessage(), e);
+ } catch (IllegalArgumentException | JwtException e) {
logger.error("Validation failed: " + e.getMessage(), e);
throw new IEMRException("Validation error: " + e.getMessage(), e);
}Likely invalid or redundant comment.
25-36: π οΈ Refactor suggestion
Use constructor injection instead of field injection.
Field injection should be avoided in favor of constructor injection for better testability and immutability.
Apply this change:
- @Autowired
- private CookieUtil cookieUtil;
- @Autowired
- private JwtUtil jwtUtil;
- @Autowired
- private RedisTemplate<String, Object> redisTemplate;
- @Autowired
- private IEMRUserRepositoryCustom iEMRUserRepositoryCustom;
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
- @Autowired
- private IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl;
- public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) {
+ public JwtAuthenticationUtil(
+ CookieUtil cookieUtil,
+ JwtUtil jwtUtil,
+ RedisTemplate<String, Object> redisTemplate,
+ IEMRUserRepositoryCustom iEMRUserRepositoryCustom,
+ IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl) {
this.cookieUtil = cookieUtil;
this.jwtUtil = jwtUtil;
+ this.redisTemplate = redisTemplate;
+ this.iEMRUserRepositoryCustom = iEMRUserRepositoryCustom;
+ this.iEMRAdminUserServiceImpl = iEMRAdminUserServiceImpl;
}Likely invalid or redundant comment.
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java (5)
31-31: LGTM - Dependencies added for JWT and Redis integration.
The necessary imports for JWT token handling, cookie management, and Redis integration have been correctly added.
Also applies to: 40-42, 68-70, 81-83, 92-99
305-309: LGTM - Role object enhanced with Sanjeevani flag.
The addition of the isSanjeevani field to the role object is implemented correctly.
648-650: LGTM - Method signature enhanced with clear documentation.
The updated method signature with additional filter parameters is well-documented and maintains backward compatibility.
923-925: Remove hardcoded encryption keys from the code.
Hardcoded encryption keys like "Piramal12Piramal" should not be present in the codebase, even if commented out. This poses a significant security risk.
971-987: Inconsistent cookie name and redundant code for retrieving JWT token.
The method getJwtTokenFromCookie is manually retrieving the cookie named "jwtToken", whereas elsewhere in the application, the cookie is named "Jwttoken". This inconsistency can lead to issues where the JWT token is not found.
Additionally, consider using the existing CookieUtil's getJwtTokenFromCookie method to avoid code duplication and maintain consistency.
| public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { | ||
| RedisTemplate<String, Object> template = new RedisTemplate<>(); | ||
| template.setConnectionFactory(factory); | ||
|
|
||
| // Use StringRedisSerializer for keys | ||
| template.setKeySerializer(new StringRedisSerializer()); | ||
|
|
||
| // Use Jackson2JsonRedisSerializer for values (objects) | ||
| Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class); | ||
| template.setValueSerializer(serializer); | ||
|
|
||
| return template; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Consider enhancing Redis serialization and connection settings.
The current Redis template configuration could be improved in two areas:
- The Jackson serializer lacks type information which could cause deserialization issues with complex objects
- Connection pooling settings are missing which could impact performance under load
Consider applying these improvements:
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Use StringRedisSerializer for keys
template.setKeySerializer(new StringRedisSerializer());
// Use Jackson2JsonRedisSerializer for values (objects)
- Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
+ Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+ serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
return template;
}
+@Bean
+public LettuceConnectionFactory redisConnectionFactory() {
+ LettucePoolingClientConfiguration poolConfig = LettucePoolingClientConfiguration.builder()
+ .poolConfig(new GenericObjectPoolConfig())
+ .build();
+
+ return new LettuceConnectionFactory(new RedisStandaloneConfiguration(), poolConfig);
+}Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rate Limit Exceeded
@indraniBan have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 34 seconds before sending another message.
| String Jwttoken = jwtUtil.generateToken(m_User.getUserName(), mUser.get(0).getUserID().toString()); | ||
| logger.info("jwt token is:" + Jwttoken); | ||
|
|
||
| User user = new User(); // Assuming the Users class exists | ||
| user.setUserID(mUser.get(0).getUserID()); | ||
| user.setUserName(mUser.get(0).getUserName()); | ||
|
|
||
| String redisKey = "user_" + mUser.get(0).getUserID(); // Use user ID to create a unique key | ||
|
|
||
| // Store the user in Redis (set a TTL of 30 minutes) | ||
| redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES); | ||
|
|
||
| // Set Jwttoken in the response cookie | ||
| cookieUtil.addJwtTokenToCookie(Jwttoken, httpResponse); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Add error handling for Redis operations.
While the JWT token generation and storage logic is correct, consider adding error handling for Redis operations to gracefully handle connection issues or storage failures.
Apply this diff:
- String redisKey = "user_" + mUser.get(0).getUserID();
- redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES);
+ try {
+ String redisKey = "user_" + mUser.get(0).getUserID();
+ redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES);
+ } catch (Exception e) {
+ logger.error("Failed to store user session in Redis", e);
+ throw new IEMRException("Session management failed");
+ }π 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.
| String Jwttoken = jwtUtil.generateToken(m_User.getUserName(), mUser.get(0).getUserID().toString()); | |
| logger.info("jwt token is:" + Jwttoken); | |
| User user = new User(); // Assuming the Users class exists | |
| user.setUserID(mUser.get(0).getUserID()); | |
| user.setUserName(mUser.get(0).getUserName()); | |
| String redisKey = "user_" + mUser.get(0).getUserID(); // Use user ID to create a unique key | |
| // Store the user in Redis (set a TTL of 30 minutes) | |
| redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES); | |
| // Set Jwttoken in the response cookie | |
| cookieUtil.addJwtTokenToCookie(Jwttoken, httpResponse); | |
| String Jwttoken = jwtUtil.generateToken(m_User.getUserName(), mUser.get(0).getUserID().toString()); | |
| logger.info("jwt token is:" + Jwttoken); | |
| User user = new User(); // Assuming the Users class exists | |
| user.setUserID(mUser.get(0).getUserID()); | |
| user.setUserName(mUser.get(0).getUserName()); | |
| try { | |
| String redisKey = "user_" + mUser.get(0).getUserID(); | |
| redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES); | |
| } catch (Exception e) { | |
| logger.error("Failed to store user session in Redis", e); | |
| throw new IEMRException("Session management failed"); | |
| } | |
| // Set Jwttoken in the response cookie | |
| cookieUtil.addJwtTokenToCookie(Jwttoken, httpResponse); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@indraniBan Understood, I'll retract the suggestion. Let me know if you need any other assistance.
| logger.info("jwt token is:" + Jwttoken); | ||
|
|
||
| User user = new User(); // Assuming the Users class exists | ||
| user.setUserID(mUser.get(0).getUserID()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check indent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
β»οΈ Duplicate comments (4)
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java (1)
969-985:β οΈ Potential issueInconsistent cookie name and redundant implementation.
The implementation has multiple issues:
- Cookie name inconsistency with other parts of the application
- Redundant implementation when CookieUtil is available
- Missing security headers for JWT cookie
Additionally, consider adding error handling for null cookies:
@GetMapping("/get-jwt-token") public ResponseEntity<String> getJwtTokenFromCookie(HttpServletRequest httpRequest) { + if (httpRequest.getCookies() == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No cookies found"); + } return cookieUtil.getJwtTokenFromCookie(httpRequest) .map(ResponseEntity::ok) .orElse(ResponseEntity.status(HttpStatus.NOT_FOUND).body("JWT token not found")); }src/main/java/com/iemr/common/utils/CookieUtil.java (3)
15-25: π οΈ Refactor suggestionAdd input validation and use constant for cookie name comparison.
- Add input validation for request and cookieName parameters
- Use a constant for cookie name comparison for maintainability
+ private static final String JWT_COOKIE_NAME = "Jwttoken"; + public Optional<String> getCookieValue(HttpServletRequest request, String cookieName) { + if (request == null || cookieName == null || cookieName.trim().isEmpty()) { + return Optional.empty(); + } Cookie[] cookies = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { - if (cookieName.equals(cookie.getName())) { + if (cookie != null && cookieName.equals(cookie.getName())) { return Optional.of(cookie.getValue()); } }
27-37:β οΈ Potential issueEnhance security configuration of JWT cookie.
Several security improvements needed:
- Validate JWT token input
- Use configurable values for cookie name and expiration
- Add SameSite attribute
- Restrict cookie domain
- Consider making secure flag mandatory for JWT cookies
+ @Value("${jwt.cookie.maxAge:86400}") // 1 day default + private int jwtCookieMaxAge; + public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response, HttpServletRequest request) { + if (Jwttoken == null || Jwttoken.trim().isEmpty()) { + throw new IllegalArgumentException("JWT token cannot be null or empty"); + } // Create a new cookie with the JWT token - Cookie cookie = new Cookie("Jwttoken", Jwttoken); + Cookie cookie = new Cookie(JWT_COOKIE_NAME, Jwttoken); cookie.setHttpOnly(true); // Prevent JavaScript access for security - cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time + cookie.setMaxAge(jwtCookieMaxAge); cookie.setPath("/"); // Make the cookie available for the entire application - if ("https".equalsIgnoreCase(request.getScheme())) { - cookie.setSecure(true); // Secure flag only on HTTPS - } + cookie.setSecure(true); // Always require HTTPS for JWT cookies + cookie.setSameSite("Strict"); // Prevent CSRF + cookie.setDomain(null); // Restrict to same domain response.addCookie(cookie); // Add the cookie to the response }
39-42:β οΈ Potential issueFix potential NPE and maintain consistency with Optional pattern.
The method needs null checking and should maintain consistency with
getCookieValueby returning Optional.- public String getJwtTokenFromCookie(HttpServletRequest request) { - return Arrays.stream(request.getCookies()) - .filter(cookie -> "Jwttoken".equals(cookie.getName())) - .map(Cookie::getValue) - .findFirst() - .orElse(null); + public Optional<String> getJwtTokenFromCookie(HttpServletRequest request) { + if (request == null || request.getCookies() == null) { + return Optional.empty(); + } + return Arrays.stream(request.getCookies()) + .filter(cookie -> JWT_COOKIE_NAME.equals(cookie.getName())) + .map(Cookie::getValue) + .findFirst(); }
π§Ή Nitpick comments (4)
src/main/java/com/iemr/common/CommonApplication.java (1)
48-51: Consider configuring timeouts or interceptors in RestTemplate if needed.The
RestTemplatebean creation is straightforward, but for production scenarios, you may want to set appropriate timeouts or use interceptors for robust error handling and performance monitoring.src/main/java/com/iemr/common/controller/users/IEMRAdminController.java (1)
303-307: Consider adding documentation for the isSanjeevani field.The addition of the isSanjeevani field to role objects should be documented to explain its purpose and usage.
Add a comment explaining the purpose of isSanjeevani:
JSONArray roles = previlegeObj.getJSONObject(serv).getJSONArray("roles"); JSONObject roleObject = new JSONObject(m_UserServiceRoleMapping.getM_Role().toString()); + // isSanjeevani flag indicates if the role has access to Sanjeevani-specific features roleObject.put("isSanjeevani", m_UserServiceRoleMapping.getIsSanjeevani()); roles.put(roleObject);src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java (2)
43-68: Enhance error handling and logging in token validation.Add proper logging and externalize error messages for better maintainability.
+ private static final String ERROR_401_PREFIX = "Error 401: Unauthorized - "; + private static final String JWT_MISSING_MESSAGE = "JWT Token is not set!"; + private static final String JWT_INVALID_MESSAGE = "Invalid JWT Token!"; + private static final String USERNAME_MISSING_MESSAGE = "Username is missing!"; public ResponseEntity<String> validateJwtToken(HttpServletRequest request) { - Optional<String> jwtTokenOpt = cookieUtil.getCookieValue(request, "Jwttoken"); + Optional<String> jwtTokenOpt = cookieUtil.getCookieValue(request, JWT_COOKIE_NAME); if (jwtTokenOpt.isEmpty()) { + logger.warn("JWT token not found in request cookies"); return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body("Error 401: Unauthorized - JWT Token is not set!"); + .body(ERROR_401_PREFIX + JWT_MISSING_MESSAGE); } String jwtToken = jwtTokenOpt.get(); // Validate the token Claims claims = jwtUtil.validateToken(jwtToken); if (claims == null) { + logger.warn("Invalid JWT token detected"); return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body("Error 401: Unauthorized - Invalid JWT Token!"); + .body(ERROR_401_PREFIX + JWT_INVALID_MESSAGE); } // Extract username from token String usernameFromToken = claims.getSubject(); if (usernameFromToken == null || usernameFromToken.isEmpty()) { + logger.warn("Username missing in JWT token"); return ResponseEntity.status(HttpStatus.UNAUTHORIZED) - .body("Error 401: Unauthorized - Username is missing!"); + .body(ERROR_401_PREFIX + USERNAME_MISSING_MESSAGE); } + logger.debug("JWT token successfully validated for user: {}", usernameFromToken); return ResponseEntity.ok(usernameFromToken); }
98-129: Improve Redis caching configuration and error handling.
- Externalize Redis configuration values
- Add error handling for Redis operations
- Use consistent key generation
+ @Value("${redis.key.prefix:user_}") + private String redisKeyPrefix; + + @Value("${redis.cache.duration.minutes:30}") + private int redisCacheDuration; + + private String generateRedisKey(String userId) { + return redisKeyPrefix + userId; + } private User getUserFromCache(String userId) { - String redisKey = "user_" + userId; // The Redis key format - User user = (User) redisTemplate.opsForValue().get(redisKey); + try { + String redisKey = generateRedisKey(userId); + User user = (User) redisTemplate.opsForValue().get(redisKey); + logger.debug("Cache {} for user ID: {}", user != null ? "hit" : "miss", userId); + return user; + } catch (Exception e) { + logger.error("Error accessing Redis cache: {}", e.getMessage()); + return null; // Fallback to DB on cache error + } } private User fetchUserFromDB(String userId) { - String redisKey = "user_" + userId; // Redis key format + String redisKey = generateRedisKey(userId); // Fetch user from DB - User user = iEMRUserRepositoryCustom.findByUserID(Long.parseLong(userId)); + try { + User user = iEMRUserRepositoryCustom.findByUserID(Long.parseLong(userId)); + if (user != null) { + try { + // Cache the user in Redis for future requests + redisTemplate.opsForValue().set(redisKey, user, redisCacheDuration, TimeUnit.MINUTES); + logger.debug("User cached in Redis with key: {}", redisKey); + } catch (Exception e) { + logger.error("Error caching user in Redis: {}", e.getMessage()); + } + } + return user; + } catch (NumberFormatException e) { + logger.error("Invalid user ID format: {}", userId); + throw e; + } }
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (6)
src/main/java/com/iemr/common/CommonApplication.java(3 hunks)src/main/java/com/iemr/common/config/RedisConfig.java(1 hunks)src/main/java/com/iemr/common/controller/users/IEMRAdminController.java(13 hunks)src/main/java/com/iemr/common/data/users/User.java(3 hunks)src/main/java/com/iemr/common/utils/CookieUtil.java(1 hunks)src/main/java/com/iemr/common/utils/JwtAuthenticationUtil.java(1 hunks)
π§ Files skipped from review as they are similar to previous changes (2)
- src/main/java/com/iemr/common/data/users/User.java
- src/main/java/com/iemr/common/config/RedisConfig.java
π Additional comments (5)
src/main/java/com/iemr/common/CommonApplication.java (2)
29-32: Imports look consistent and necessary.
These new imports from org.springframework.data.redis.* are used for Redis connectivity, key/value serialization, and are relevant to the new Redis template bean. No issues found here.
36-36: Confirm User implements Serializable.
Since User objects are being serialized into Redis, ensure User (and any nested fields) fully supports serialization. Maintaining serialization compatibility is crucial to prevent runtime errors.
src/main/java/com/iemr/common/controller/users/IEMRAdminController.java (3)
31-31: LGTM! Dependencies and autowiring look good.
The new dependencies and autowired components are properly configured for JWT implementation and Redis session management.
Also applies to: 40-41, 68-70, 92-99
143-143: LGTM! Method signature updated correctly.
The addition of HttpServletResponse parameter is necessary for setting the JWT cookie in the response.
921-923: Remove commented-out code with hardcoded encryption keys.
This is a security concern that was previously identified.
| @Bean | ||
| public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { | ||
| RedisTemplate<String, Object> template = new RedisTemplate<>(); | ||
| template.setConnectionFactory(factory); | ||
|
|
||
| // Use StringRedisSerializer for keys (userId) | ||
| template.setKeySerializer(new StringRedisSerializer()); | ||
|
|
||
| // Use Jackson2JsonRedisSerializer for values (Users objects) | ||
| Jackson2JsonRedisSerializer<User> serializer = new Jackson2JsonRedisSerializer<>(User.class); | ||
| template.setValueSerializer(serializer); | ||
|
|
||
| return template; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Promote type-safety in the Redis template.
Although defining RedisTemplate<String, Object> works for storing various objects, if you only plan to store User objects, consider using a more specific type parameter (RedisTemplate<String, User>) for improved type safety. Also, validate that the Jackson serializer handles all required fields in the User class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not required
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rate Limit Exceeded
@indraniBan have exceeded the limit for the number of chat messages per hour. Please wait 0 minutes and 33 seconds before sending another message.
| @Autowired | ||
| private CookieUtil cookieUtil; | ||
| @Autowired | ||
| private JwtUtil jwtUtil; | ||
| @Autowired | ||
| private RedisTemplate<String, Object> redisTemplate; | ||
| @Autowired | ||
| private IEMRUserRepositoryCustom iEMRUserRepositoryCustom; | ||
| private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); | ||
|
|
||
| @Autowired | ||
| private IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl; | ||
|
|
||
| public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { | ||
| this.cookieUtil = cookieUtil; | ||
| this.jwtUtil = jwtUtil; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Improve dependency injection pattern.
Current implementation mixes field and constructor injection, which can lead to initialization issues:
- Constructor is missing RedisTemplate and other autowired dependencies
- Field injection should be avoided for better testability
- Constructor @Autowired is redundant since Spring 4.3
- @Autowired
- private CookieUtil cookieUtil;
- @Autowired
- private JwtUtil jwtUtil;
- @Autowired
- private RedisTemplate<String, Object> redisTemplate;
- @Autowired
- private IEMRUserRepositoryCustom iEMRUserRepositoryCustom;
private final Logger logger = LoggerFactory.getLogger(this.getClass().getName());
- @Autowired
- private IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl;
- @Autowired
- public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) {
+ public JwtAuthenticationUtil(
+ CookieUtil cookieUtil,
+ JwtUtil jwtUtil,
+ RedisTemplate<String, Object> redisTemplate,
+ IEMRUserRepositoryCustom iEMRUserRepositoryCustom,
+ IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl) {
this.cookieUtil = cookieUtil;
this.jwtUtil = jwtUtil;
+ this.redisTemplate = redisTemplate;
+ this.iEMRUserRepositoryCustom = iEMRUserRepositoryCustom;
+ this.iEMRAdminUserServiceImpl = iEMRAdminUserServiceImpl;
}π 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.
| @Autowired | |
| private CookieUtil cookieUtil; | |
| @Autowired | |
| private JwtUtil jwtUtil; | |
| @Autowired | |
| private RedisTemplate<String, Object> redisTemplate; | |
| @Autowired | |
| private IEMRUserRepositoryCustom iEMRUserRepositoryCustom; | |
| private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); | |
| @Autowired | |
| private IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl; | |
| public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { | |
| this.cookieUtil = cookieUtil; | |
| this.jwtUtil = jwtUtil; | |
| } | |
| private final CookieUtil cookieUtil; | |
| private final JwtUtil jwtUtil; | |
| private final RedisTemplate<String, Object> redisTemplate; | |
| private final IEMRUserRepositoryCustom iEMRUserRepositoryCustom; | |
| private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); | |
| private final IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl; | |
| public JwtAuthenticationUtil( | |
| CookieUtil cookieUtil, | |
| JwtUtil jwtUtil, | |
| RedisTemplate<String, Object> redisTemplate, | |
| IEMRUserRepositoryCustom iEMRUserRepositoryCustom, | |
| IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl) { | |
| this.cookieUtil = cookieUtil; | |
| this.jwtUtil = jwtUtil; | |
| this.redisTemplate = redisTemplate; | |
| this.iEMRUserRepositoryCustom = iEMRUserRepositoryCustom; | |
| this.iEMRAdminUserServiceImpl = iEMRAdminUserServiceImpl; | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
working fine
There was a problem hiding this comment.
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!
| public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { | ||
| try { | ||
| // Validate JWT token and extract claims | ||
| Claims claims = jwtUtil.validateToken(jwtToken); | ||
|
|
||
| if (claims == null) { | ||
| throw new IEMRException("Invalid JWT token."); | ||
| } | ||
|
|
||
| String userId = claims.get("userId", String.class); | ||
|
|
||
| // Check if user data is present in Redis | ||
| User user = getUserFromCache(userId); | ||
| if (user == null) { | ||
| // If not in Redis, fetch from DB and cache the result | ||
| user = fetchUserFromDB(userId); | ||
| } | ||
| if (user == null) { | ||
| throw new IEMRException("Invalid User ID."); | ||
| } | ||
|
|
||
| return true; // Valid userId and JWT token | ||
| } catch (Exception e) { | ||
| logger.error("Validation failed: " + e.getMessage(), e); | ||
| throw new IEMRException("Validation error: " + e.getMessage(), e); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ Refactor suggestion
Improve error handling and reduce redundancy.
- Catch specific exceptions instead of generic Exception
- Remove redundant null check
- Add proper logging for each validation step
public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException {
try {
+ logger.debug("Starting JWT token validation");
// Validate JWT token and extract claims
Claims claims = jwtUtil.validateToken(jwtToken);
if (claims == null) {
+ logger.warn("JWT token validation failed: null claims");
throw new IEMRException("Invalid JWT token.");
}
String userId = claims.get("userId", String.class);
+ if (userId == null || userId.trim().isEmpty()) {
+ logger.warn("User ID missing in JWT token");
+ throw new IEMRException("User ID is missing in token.");
+ }
// Check if user data is present in Redis
User user = getUserFromCache(userId);
if (user == null) {
+ logger.debug("User not found in cache, fetching from DB");
// If not in Redis, fetch from DB and cache the result
user = fetchUserFromDB(userId);
- }
- if (user == null) {
- throw new IEMRException("Invalid User ID.");
+ if (user == null) {
+ logger.warn("User not found in DB for ID: {}", userId);
+ throw new IEMRException("Invalid User ID.");
+ }
}
+ logger.debug("JWT token successfully validated for user ID: {}", userId);
return true; // Valid userId and JWT token
- } catch (Exception e) {
+ } catch (IEMRException e) {
+ throw e;
+ } catch (NumberFormatException e) {
+ logger.error("Invalid user ID format: {}", e.getMessage());
+ throw new IEMRException("Invalid User ID format.", e);
+ } catch (RuntimeException e) {
logger.error("Validation failed: " + e.getMessage(), e);
throw new IEMRException("Validation error: " + e.getMessage(), e);
}
}π 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.
| public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { | |
| try { | |
| // Validate JWT token and extract claims | |
| Claims claims = jwtUtil.validateToken(jwtToken); | |
| if (claims == null) { | |
| throw new IEMRException("Invalid JWT token."); | |
| } | |
| String userId = claims.get("userId", String.class); | |
| // Check if user data is present in Redis | |
| User user = getUserFromCache(userId); | |
| if (user == null) { | |
| // If not in Redis, fetch from DB and cache the result | |
| user = fetchUserFromDB(userId); | |
| } | |
| if (user == null) { | |
| throw new IEMRException("Invalid User ID."); | |
| } | |
| return true; // Valid userId and JWT token | |
| } catch (Exception e) { | |
| logger.error("Validation failed: " + e.getMessage(), e); | |
| throw new IEMRException("Validation error: " + e.getMessage(), e); | |
| } | |
| } | |
| public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { | |
| try { | |
| logger.debug("Starting JWT token validation"); | |
| // Validate JWT token and extract claims | |
| Claims claims = jwtUtil.validateToken(jwtToken); | |
| if (claims == null) { | |
| logger.warn("JWT token validation failed: null claims"); | |
| throw new IEMRException("Invalid JWT token."); | |
| } | |
| String userId = claims.get("userId", String.class); | |
| if (userId == null || userId.trim().isEmpty()) { | |
| logger.warn("User ID missing in JWT token"); | |
| throw new IEMRException("User ID is missing in token."); | |
| } | |
| // Check if user data is present in Redis | |
| User user = getUserFromCache(userId); | |
| if (user == null) { | |
| logger.debug("User not found in cache, fetching from DB"); | |
| // If not in Redis, fetch from DB and cache the result | |
| user = fetchUserFromDB(userId); | |
| if (user == null) { | |
| logger.warn("User not found in DB for ID: {}", userId); | |
| throw new IEMRException("Invalid User ID."); | |
| } | |
| } | |
| logger.debug("JWT token successfully validated for user ID: {}", userId); | |
| return true; // Valid userId and JWT token | |
| } catch (IEMRException e) { | |
| throw e; | |
| } catch (NumberFormatException e) { | |
| logger.error("Invalid user ID format: {}", e.getMessage()); | |
| throw new IEMRException("Invalid User ID format.", e); | |
| } catch (RuntimeException e) { | |
| logger.error("Validation failed: " + e.getMessage(), e); | |
| throw new IEMRException("Validation error: " + e.getMessage(), e); | |
| } | |
| } |
|
|
ravishanigarapu
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks ok
| // String decryptPassword = aesUtil.decrypt("Piramal12Piramal", | ||
| // m_User.getPassword()); | ||
| // logger.info("decryptPassword : " + m_User.getPassword()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented lines code



π Description
JIRA ID:
Please provide a summary of the change and the motivation behind it. Include relevant context and details.
β Type of Change
βΉοΈ 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
Release Notes
New Features
Bug Fixes
Chores