-
Notifications
You must be signed in to change notification settings - Fork 0
Dev #10
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |||||||||||||||||||||||||||||||||||||||||
| import com.techtorque.time_logging_service.dto.request.TimeLogUpdateRequest; | ||||||||||||||||||||||||||||||||||||||||||
| import com.techtorque.time_logging_service.dto.response.TimeLogResponse; | ||||||||||||||||||||||||||||||||||||||||||
| import com.techtorque.time_logging_service.dto.response.TimeLogSummaryResponse; | ||||||||||||||||||||||||||||||||||||||||||
| import com.techtorque.time_logging_service.exception.UnauthorizedAccessException; | ||||||||||||||||||||||||||||||||||||||||||
| import com.techtorque.time_logging_service.service.TimeLogService; | ||||||||||||||||||||||||||||||||||||||||||
| import io.swagger.v3.oas.annotations.Operation; | ||||||||||||||||||||||||||||||||||||||||||
| import io.swagger.v3.oas.annotations.Parameter; | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -63,12 +64,12 @@ public TimeLogController(TimeLogService timeLogService) { | |||||||||||||||||||||||||||||||||||||||||
| @ApiResponse(responseCode = "403", description = "Forbidden - insufficient permissions") | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| @PostMapping | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasRole('EMPLOYEE')") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<TimeLogResponse> createTimeLog( | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Employee ID from authentication token", required = true) | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader(value = "X-User-Subject") String employeeId, | ||||||||||||||||||||||||||||||||||||||||||
| @Valid @RequestBody TimeLogRequest request) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| TimeLogResponse response = timeLogService.createTimeLog(employeeId, request); | ||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.status(HttpStatus.CREATED).body(response); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -88,7 +89,7 @@ public ResponseEntity<TimeLogResponse> createTimeLog( | |||||||||||||||||||||||||||||||||||||||||
| @ApiResponse(responseCode = "403", description = "Forbidden") | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| @GetMapping | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<List<TimeLogResponse>> getMyTimeLogs( | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Employee ID from authentication token", required = true) | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader("X-User-Subject") String userId, | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -97,11 +98,11 @@ public ResponseEntity<List<TimeLogResponse>> getMyTimeLogs( | |||||||||||||||||||||||||||||||||||||||||
| @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate from, | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "End date for filtering (YYYY-MM-DD)") | ||||||||||||||||||||||||||||||||||||||||||
| @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate to) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| List<TimeLogResponse> responses; | ||||||||||||||||||||||||||||||||||||||||||
| // Admin can see all time logs | ||||||||||||||||||||||||||||||||||||||||||
| if (roles.contains("ADMIN")) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Admin and Super Admin can see all time logs | ||||||||||||||||||||||||||||||||||||||||||
| if (roles.contains("ADMIN") || roles.contains("SUPER_ADMIN")) { | ||||||||||||||||||||||||||||||||||||||||||
| if (from != null && to != null) { | ||||||||||||||||||||||||||||||||||||||||||
| // For admin with date range, get all logs and filter (or create new method) | ||||||||||||||||||||||||||||||||||||||||||
| responses = timeLogService.getAllTimeLogs().stream() | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -118,7 +119,7 @@ public ResponseEntity<List<TimeLogResponse>> getMyTimeLogs( | |||||||||||||||||||||||||||||||||||||||||
| responses = timeLogService.getAllTimeLogsByEmployee(userId); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(responses); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -138,15 +139,15 @@ public ResponseEntity<List<TimeLogResponse>> getMyTimeLogs( | |||||||||||||||||||||||||||||||||||||||||
| @ApiResponse(responseCode = "404", description = "Time log not found") | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| @GetMapping("/{logId}") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<TimeLogResponse> getTimeLogById( | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Time log ID", required = true) | ||||||||||||||||||||||||||||||||||||||||||
| @PathVariable String logId, | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "User ID from authentication token") | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader(value = "X-User-Subject", required = false) String userId, | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "User role from authentication token") | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader(value = "X-User-Role", required = false) String userRole) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| TimeLogResponse response = timeLogService.getTimeLogByIdWithAuthorization(logId, userId, userRole); | ||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(response); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -167,14 +168,14 @@ public ResponseEntity<TimeLogResponse> getTimeLogById( | |||||||||||||||||||||||||||||||||||||||||
| @ApiResponse(responseCode = "404", description = "Time log not found") | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| @PutMapping("/{logId}") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasRole('EMPLOYEE')") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<TimeLogResponse> updateTimeLog( | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Time log ID", required = true) | ||||||||||||||||||||||||||||||||||||||||||
| @PathVariable String logId, | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Employee ID from authentication token", required = true) | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader("X-User-Subject") String employeeId, | ||||||||||||||||||||||||||||||||||||||||||
| @Valid @RequestBody TimeLogUpdateRequest request) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| TimeLogResponse response = timeLogService.updateTimeLogWithAuthorization(logId, employeeId, request); | ||||||||||||||||||||||||||||||||||||||||||
| return ResponseEntity.ok(response); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -194,13 +195,20 @@ public ResponseEntity<TimeLogResponse> updateTimeLog( | |||||||||||||||||||||||||||||||||||||||||
| @ApiResponse(responseCode = "404", description = "Time log not found") | ||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||
| @DeleteMapping("/{logId}") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasRole('EMPLOYEE')") | ||||||||||||||||||||||||||||||||||||||||||
| @PreAuthorize("hasAnyRole('EMPLOYEE', 'ADMIN', 'SUPER_ADMIN')") | ||||||||||||||||||||||||||||||||||||||||||
| public ResponseEntity<Void> deleteTimeLog( | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Time log ID", required = true) | ||||||||||||||||||||||||||||||||||||||||||
| @PathVariable String logId, | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Employee ID from authentication token", required = true) | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader("X-User-Subject") String employeeId) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "Employee ID from authentication token", required = false) | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader(value = "X-User-Subject", required = false) String employeeId, | ||||||||||||||||||||||||||||||||||||||||||
| @Parameter(description = "User role from authentication token", required = false) | ||||||||||||||||||||||||||||||||||||||||||
| @RequestHeader(value = "X-User-Roles", required = false) String userRoles) { | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // If header is missing, check if user is admin (can delete any log) | ||||||||||||||||||||||||||||||||||||||||||
| if (employeeId == null || employeeId.isEmpty()) { | ||||||||||||||||||||||||||||||||||||||||||
| throw new UnauthorizedAccessException("User identification missing. Please ensure you are logged in."); | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+202
to
+210
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incomplete authorization logic and unused parameter. Several issues with this implementation:
Clarify the intended behavior. If admins should be able to delete any log: @Parameter(description = "Employee ID from authentication token", required = false)
@RequestHeader(value = "X-User-Subject", required = false) String employeeId,
@Parameter(description = "User role from authentication token", required = false)
@RequestHeader(value = "X-User-Roles", required = false) String userRoles) {
- // If header is missing, check if user is admin (can delete any log)
- if (employeeId == null || employeeId.isEmpty()) {
- throw new UnauthorizedAccessException("User identification missing. Please ensure you are logged in.");
- }
+ // Parse roles for admin check
+ boolean isAdmin = userRoles != null &&
+ (Arrays.asList(userRoles.split(",")).contains("ADMIN") ||
+ Arrays.asList(userRoles.split(",")).contains("SUPER_ADMIN"));
+
+ // If not admin, employeeId is required
+ if (!isAdmin && (employeeId == null || employeeId.isEmpty())) {
+ throw new UnauthorizedAccessException("User identification missing. Please ensure you are logged in.");
+ }
- timeLogService.deleteTimeLogWithAuthorization(logId, employeeId);
+ // Pass role info to service layer for proper authorization
+ timeLogService.deleteTimeLogWithAuthorization(logId, employeeId, isAdmin);Note: You'll need to update the service method signature accordingly.
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| timeLogService.deleteTimeLogWithAuthorization(logId, employeeId); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| timeLogService.deleteTimeLogWithAuthorization(logId, employeeId); | |
| boolean isAdmin = false; | |
| if (userRoles != null && !userRoles.isEmpty()) { | |
| String[] roles = userRoles.split(","); | |
| for (String role : roles) { | |
| String trimmedRole = role.trim().toUpperCase(); | |
| if (trimmedRole.equals("ADMIN") || trimmedRole.equals("SUPER_ADMIN")) { | |
| isAdmin = true; | |
| break; | |
| } | |
| } | |
| } | |
| if (isAdmin) { | |
| // Admins can delete any log | |
| timeLogService.deleteTimeLogAsAdmin(logId); | |
| } else { | |
| // Employees can only delete their own logs | |
| timeLogService.deleteTimeLogWithAuthorization(logId, employeeId); | |
| } |
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.
🧩 Analysis chain
Verify SUPER_ADMIN role inclusion across all endpoints.
SUPER_ADMIN has been added consistently to most endpoints, which aligns with granting elevated privileges. However, lines 231 and 281 (getTimeLogsForService and getTimeLogsForProject) still use
@PreAuthorize("hasAnyRole('CUSTOMER', 'EMPLOYEE', 'ADMIN')")without SUPER_ADMIN. Confirm whether this exclusion is intentional or an oversight.Run the following script to identify all @PreAuthorize annotations and verify consistency:
Also applies to: 92-92, 142-142, 171-171, 198-198, 257-257, 299-299
🏁 Script executed:
Length of output: 1720
Add SUPER_ADMIN to service/project-level time log queries for consistency.
The SUPER_ADMIN role has been correctly added to employee-focused endpoints (createTimeLog, getMyTimeLogs, getTimeLogById, updateTimeLog, deleteTimeLog, getSummary, getEmployeeStats). However, lines 231 and 281 still lack SUPER_ADMIN:
getTimeLogsForService-@PreAuthorize("hasAnyRole('CUSTOMER', 'EMPLOYEE', 'ADMIN')")getTimeLogsForProject-@PreAuthorize("hasAnyRole('CUSTOMER', 'EMPLOYEE', 'ADMIN')")SUPER_ADMIN should have access to all time log data, including service and project-level queries. Add 'SUPER_ADMIN' to both annotations.
🤖 Prompt for AI Agents