Skip to content

Feat/comment controller - #55

Merged
annikaholmqvist94 merged 5 commits into
mainfrom
feat/comment-controller
Mar 31, 2026
Merged

Feat/comment controller#55
annikaholmqvist94 merged 5 commits into
mainfrom
feat/comment-controller

Conversation

@annikaholmqvist94

@annikaholmqvist94 annikaholmqvist94 commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Added endpoints for basic comment functionality, Closes #27

Summary by CodeRabbit

  • New Features

    • Users can create, view, update, and delete comments on records.
    • Retrieve and count comments per record; counts and list access now respect the authenticated user's access.
  • Chores

    • Integrated Spring Security framework and added password hashing support.

@annikaholmqvist94 annikaholmqvist94 added this to the Controller milestone Mar 30, 2026
@annikaholmqvist94 annikaholmqvist94 added the enhancement New feature or request label Mar 30, 2026
@coderabbitai

coderabbitai Bot commented Mar 30, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds Spring Security dependency, a permissive SecurityConfig, a new CommentController with five REST endpoints using authenticated user context, and updates CommentService.countByRecord to require a User and perform an authorization check before counting comments.

Changes

Cohort / File(s) Summary
Build
pom.xml
Added org.springframework.boot:spring-boot-starter-security dependency.
Security config
src/main/java/org/example/vet1177/security/SecurityConfig.java
New configuration class providing a permissive SecurityFilterChain (CSRF disabled, anyRequest().permitAll()) and a BCryptPasswordEncoder bean.
Comment API
src/main/java/org/example/vet1177/controllers/CommentController.java
New @RestController at /api/comments exposing create, getByRecord, update, delete, and countByRecord endpoints; injects authenticated User into handlers and delegates to CommentService.
Comment service
src/main/java/org/example/vet1177/services/CommentService.java
Signature change: countByRecord(UUID recordId)countByRecord(UUID recordId, User currentUser); now loads MedicalRecord and calls commentPolicy.canView(currentUser, record) before returning repository count.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client as Client
  participant Controller as CommentController
  participant Service as CommentService
  participant Policy as CommentPolicy
  participant Repo as CommentRepository
  participant MRRepo as MedicalRecordRepository

  Client->>Controller: GET /api/comments/record/{recordId}/count
  Controller->>Service: countByRecord(recordId, currentUser)
  Service->>MRRepo: findById(recordId)
  MRRepo-->>Service: MedicalRecord
  Service->>Policy: canView(currentUser, MedicalRecord)
  Policy-->>Service: allowed / denied
  alt allowed
    Service->>Repo: countByMedicalRecordId(recordId)
    Repo-->>Service: count (Long)
    Service-->>Controller: count
    Controller-->>Client: 200 OK (count)
  else denied
    Service-->>Controller: throw ResourceNotFound/AccessDenied
    Controller-->>Client: 403/404
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • johanbriger
  • lindaeskilsson
  • TatjanaTrajkovic

Poem

🐰 I hopped into code as spring winds blew,
A lock was added, yet all still new,
Comments now march through controllers and rules,
Policies check like careful little tools,
I celebrate with carrots and a bug-free view 🥕✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feat/comment controller' is vague and partially related; it references a real part of the changeset (CommentController) but uses non-descriptive phrasing without explaining the core feature being added. Revise the title to be more descriptive, such as 'Add comment management endpoints with authentication and access control' to better convey the main changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The pull request successfully implements the primary objective of adding a Comment Controller with HTTP endpoints for basic comment functionality, including create, retrieve, update, delete, and count operations.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing comment management functionality: CommentController endpoints, security configuration integration, access control enforcement, and supporting Maven dependency additions.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/comment-controller

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/main/java/org/example/vet1177/controllers/CommentController.java (1)

34-42: Prefer 201 Created for successful comment creation.

Line 34 currently returns 200 OK; for resource creation, 201 Created is the better REST contract.

HTTP status adjustment
-        return ResponseEntity.ok(
+        return ResponseEntity.status(201).body(
                 CommentResponse.from(
                         commentService.create(
                                 request.recordId(),
                                 request.body(),
                                 currentUser
                         )
                 )
         );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/controllers/CommentController.java` around
lines 34 - 42, Change the controller to return HTTP 201 for successful comment
creation: in CommentController replace the ResponseEntity.ok(...) that wraps
CommentResponse.from(commentService.create(...)) with a
ResponseEntity.status(HttpStatus.CREATED).body(CommentResponse.from(...)) (or
ResponseEntity.created(URI).body(...) if you want to include a Location header);
ensure HttpStatus is imported and keep the same call to
commentService.create(...) and CommentResponse.from(...) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pom.xml`:
- Around line 80-83: Create a new configuration class (e.g., ApiSecurityConfig)
and add a `@Bean` method SecurityFilterChain securityFilterChain(HttpSecurity
http) that configures API-specific security: disable formLogin and default login
redirects, disable or selectively configure CSRF for stateless API endpoints,
set sessionManagement to SessionCreationPolicy.STATELESS, configure
exceptionHandling to return 401/403 (instead of redirect), permit anonymous
access to endpoints like /api/auth/** and /api/public/** and require
authentication for other /api/** paths, and enable CORS; also expose a
PasswordEncoder bean (e.g., BCryptPasswordEncoder) and, if you use JWT, ensure
AuthenticationManager/ Jwt filters are wired into the filter chain. Ensure the
class and method names (ApiSecurityConfig and securityFilterChain) are used so
reviewers can find and verify the configuration.

In `@src/main/java/org/example/vet1177/controllers/CommentController.java`:
- Around line 86-88: The countByRecord endpoint leaks metadata because it calls
commentService.countByRecord(recordId) without an authenticated user check;
change the controller and service so countByRecord accepts the currentUser
(e.g., Principal or User) and in CommentService.countByRecord load the medical
record by recordId, call commentPolicy.canView(currentUser, record) and only if
authorized return commentRepository.countByMedicalRecordId(recordId), otherwise
throw an appropriate access denied exception.
- Around line 30-33: The controller methods create, getByRecord, update, and
delete currently inject `@AuthenticationPrincipal` User which is unsafe because
User is a JPA entity and not a UserDetails; change each method signature to
accept `@AuthenticationPrincipal` UserDetails principal (e.g., in create,
getByRecord, update, delete) and then resolve the domain User inside the method
via your UserRepository (e.g.,
userRepository.findByUsername(principal.getUsername()) or
userService.loadByUsername) and handle the case where the domain User is missing
(return 401/404 as appropriate); ensure you update references to the old User
parameter in these methods to use the resolved domain User and keep
request/response types (CreateCommentRequest, CommentResponse) unchanged.

---

Nitpick comments:
In `@src/main/java/org/example/vet1177/controllers/CommentController.java`:
- Around line 34-42: Change the controller to return HTTP 201 for successful
comment creation: in CommentController replace the ResponseEntity.ok(...) that
wraps CommentResponse.from(commentService.create(...)) with a
ResponseEntity.status(HttpStatus.CREATED).body(CommentResponse.from(...)) (or
ResponseEntity.created(URI).body(...) if you want to include a Location header);
ensure HttpStatus is imported and keep the same call to
commentService.create(...) and CommentResponse.from(...) unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 784bc378-fdcd-4fed-a69e-716211ee9920

📥 Commits

Reviewing files that changed from the base of the PR and between d9592eb and 231cdec.

📒 Files selected for processing (2)
  • pom.xml
  • src/main/java/org/example/vet1177/controllers/CommentController.java

Comment thread pom.xml
Comment on lines +80 to +83
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether custom Spring Security configuration exists.
# Expected: at least one SecurityFilterChain bean suitable for API usage.

rg -nP --type=java -C3 'SecurityFilterChain|@EnableWebSecurity|HttpSecurity|csrf\s*\(' src/main/java
rg -nP --type=java -C3 '@Bean\s+.*SecurityFilterChain'

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


Add explicit Spring Security configuration to handle API requests properly.

The spring-boot-starter-security dependency has been added but no SecurityFilterChain bean exists to configure API-specific security (CSRF handling, authentication endpoints, session policies). Without this configuration, API write operations will return 401/403 errors and may trigger unexpected login redirects.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pom.xml` around lines 80 - 83, Create a new configuration class (e.g.,
ApiSecurityConfig) and add a `@Bean` method SecurityFilterChain
securityFilterChain(HttpSecurity http) that configures API-specific security:
disable formLogin and default login redirects, disable or selectively configure
CSRF for stateless API endpoints, set sessionManagement to
SessionCreationPolicy.STATELESS, configure exceptionHandling to return 401/403
(instead of redirect), permit anonymous access to endpoints like /api/auth/**
and /api/public/** and require authentication for other /api/** paths, and
enable CORS; also expose a PasswordEncoder bean (e.g., BCryptPasswordEncoder)
and, if you use JWT, ensure AuthenticationManager/ Jwt filters are wired into
the filter chain. Ensure the class and method names (ApiSecurityConfig and
securityFilterChain) are used so reviewers can find and verify the
configuration.

Comment on lines +30 to +33
public ResponseEntity<CommentResponse> create(
@Valid @RequestBody CreateCommentRequest request,
@AuthenticationPrincipal User currentUser) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify principal/type compatibility and all affected injection points.
# Expected:
# - User entity should implement UserDetails OR controller should consume UserDetails/custom principal.
# - All `@AuthenticationPrincipal` usages should align with configured Authentication principal type.

rg -nP --type=java -C3 'class\s+User\b|implements\s+UserDetails' src/main/java/org/example/vet1177/entities/User.java
rg -nP --type=java -C2 '@AuthenticationPrincipal\s+User\b|@AuthenticationPrincipal\s+.*UserDetails\b' src/main/java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 2439


🏁 Script executed:

# Find security configuration files
fd -e java -e yml -e yaml -e properties | xargs grep -l "SecurityConfig\|UserDetailsService\|@EnableWebSecurity\|AuthenticationProvider" 2>/dev/null | head -20

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Search for UserDetailsService implementation
rg -n "implements UserDetailsService|class.*UserDetailsService" --type=java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Check if User is registered or used as principal in any configuration
rg -n "User\s*principal|new User|authentication.*User" --type=java -C2 | head -50

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 601


🏁 Script executed:

# Search for any Spring Security configuration (including annotations)
rg -n "@EnableWebSecurity|@Configuration|SecurityFilterChain|WebSecurityConfigurerAdapter" --type=java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Search for authentication/security in application.properties or application.yml
fd -e properties -e yml -e yaml | xargs cat 2>/dev/null

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 1150


🏁 Script executed:

# Check if there's a custom principal class or custom UserDetails implementation
rg -n "implements UserDetails|extends User|class.*Principal" --type=java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Look for authentication manager or provider configuration
rg -n "AuthenticationManager|AuthenticationProvider|DaoAuthenticationProvider" --type=java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Search more broadly for any Spring Security related code
rg -n "spring.security|@Bean.*SecurityFilterChain|UserDetailsService" --type=java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Check pom.xml or build.gradle for spring-security dependency
fd -e pom.xml -e gradle.build | xargs cat 2>/dev/null | grep -i "spring-security\|security"

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# List all Java files in the project to understand structure
find src -name "*.java" -type f | head -30

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 2143


🏁 Script executed:

# Check the entire User entity class definition
cat -n src/main/java/org/example/vet1177/entities/User.java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 4598


🏁 Script executed:

# Check if Spring Security is even a dependency - search pom.xml in root
find . -name "pom.xml" -o -name "build.gradle" | head -5

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 97


🏁 Script executed:

# Search for any authentication annotation usage or auth filter
rg -n "@RequestHeader.*Authorization|@CookieValue|HttpServletRequest.*getHeader|Authorization" --type=java | head -20

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Check if there's any servlet filter or interceptor for authentication
rg -n "Filter|Interceptor|@Component|@WebFilter" --type=java | grep -i "auth\|security\|filter" | head -20

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


🏁 Script executed:

# Look at the main application file to see what's configured
cat -n src/main/java/org/example/vet1177/Vet1177Application.java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 504


🏁 Script executed:

# Check pom.xml for dependencies, especially spring-security
cat -n pom.xml | head -100

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 4027


🏁 Script executed:

# Search for any Bean definitions that might handle authentication
rg -n "@Bean" --type=java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 70


@AuthenticationPrincipal User is unsafe—User entity does not implement UserDetails.

Lines 32, 50, 66, and 79 inject @AuthenticationPrincipal User currentUser, but User is a JPA entity without UserDetails implementation. With Spring Security auto-configuration active, the principal type mismatch will cause null injection or runtime ClassCastException when authentication is triggered, breaking all authenticated endpoints.

Use @AuthenticationPrincipal UserDetails principal and resolve the domain user separately:

 public ResponseEntity<CommentResponse> create(
         `@Valid` `@RequestBody` CreateCommentRequest request,
-        `@AuthenticationPrincipal` User currentUser) {
+        `@AuthenticationPrincipal` UserDetails principal) {
+
+    User currentUser = userService.findByEmail(principal.getUsername());

Apply the same pattern to getByRecord (line 50), update (line 66), and delete (line 79).

📝 Committable suggestion

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

Suggested change
public ResponseEntity<CommentResponse> create(
@Valid @RequestBody CreateCommentRequest request,
@AuthenticationPrincipal User currentUser) {
public ResponseEntity<CommentResponse> create(
`@Valid` `@RequestBody` CreateCommentRequest request,
`@AuthenticationPrincipal` UserDetails principal) {
User currentUser = userService.findByEmail(principal.getUsername());
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/controllers/CommentController.java` around
lines 30 - 33, The controller methods create, getByRecord, update, and delete
currently inject `@AuthenticationPrincipal` User which is unsafe because User is a
JPA entity and not a UserDetails; change each method signature to accept
`@AuthenticationPrincipal` UserDetails principal (e.g., in create, getByRecord,
update, delete) and then resolve the domain User inside the method via your
UserRepository (e.g., userRepository.findByUsername(principal.getUsername()) or
userService.loadByUsername) and handle the case where the domain User is missing
(return 401/404 as appropriate); ensure you update references to the old User
parameter in these methods to use the resolved domain User and keep
request/response types (CreateCommentRequest, CommentResponse) unchanged.

Comment on lines +86 to +88
@GetMapping("/record/{recordId}/count")
public ResponseEntity<Long> countByRecord(@PathVariable UUID recordId) {
return ResponseEntity.ok(commentService.countByRecord(recordId));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

countByRecord lacks authorization context and can leak record metadata.

Line 87 exposes count by recordId without currentUser, and the related service method has no policy check. That allows unauthorized users to infer activity on records via ID enumeration.

Suggested fix (controller + service contract)
-    public ResponseEntity<Long> countByRecord(`@PathVariable` UUID recordId) {
-        return ResponseEntity.ok(commentService.countByRecord(recordId));
+    public ResponseEntity<Long> countByRecord(
+            `@PathVariable` UUID recordId,
+            `@AuthenticationPrincipal` User currentUser) {
+        return ResponseEntity.ok(commentService.countByRecord(recordId, currentUser));
     }
// In CommentService:
// 1) Load record
// 2) commentPolicy.canView(currentUser, record)
// 3) return commentRepository.countByMedicalRecordId(recordId)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/controllers/CommentController.java` around
lines 86 - 88, The countByRecord endpoint leaks metadata because it calls
commentService.countByRecord(recordId) without an authenticated user check;
change the controller and service so countByRecord accepts the currentUser
(e.g., Principal or User) and in CommentService.countByRecord load the medical
record by recordId, call commentPolicy.canView(currentUser, record) and only if
authorized return commentRepository.countByMedicalRecordId(recordId), otherwise
throw an appropriate access denied exception.

…ontroller` and `CommentService`

- Require `currentUser` for counting comments.
- Introduce `SecurityConfig` with temporary permissive access.
- Enforce access control via `CommentPolicy`.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/main/java/org/example/vet1177/controllers/CommentController.java (1)

30-33: ⚠️ Potential issue | 🔴 Critical

Unresolved principal-binding risk across all endpoints.

This still injects @AuthenticationPrincipal User directly. Given current security setup, this can resolve to null (or incompatible principal type) and break service/policy calls at runtime.

#!/bin/bash
# Verify principal type compatibility and direct User principal injection.
rg -nP --type=java -C3 'class\s+User\b|implements\s+UserDetails' src/main/java/org/example/vet1177/entities/User.java
rg -nP --type=java -C2 '@AuthenticationPrincipal\s+User\b' src/main/java/org/example/vet1177/controllers/CommentController.java

Also applies to: 48-50, 63-67, 77-80, 88-90

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/controllers/CommentController.java` around
lines 30 - 33, The controller methods (e.g., CommentController.create) currently
inject `@AuthenticationPrincipal` User currentUser which may be null or an
incompatible principal type; change the parameter to accept
java.security.Principal or org.springframework.security.core.Authentication
(e.g., Principal principal or Authentication auth) and resolve the application
User explicitly via your user lookup (e.g.,
UserService.findByUsername(principal.getName())) with null/incompatible-type
checks; update all affected methods (the create method and the other endpoints
flagged) to validate the resolved User and throw a 401/appropriate exception
when absent instead of assuming non-null injection, and add clear error
handling/logging for incompatible principal types.
🧹 Nitpick comments (1)
src/main/java/org/example/vet1177/controllers/CommentController.java (1)

34-42: Prefer 201 Created for successful comment creation.

POST /api/comments currently returns 200 OK; consider returning 201 Created to match resource-creation semantics.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/controllers/CommentController.java` around
lines 34 - 42, Change the POST handler in CommentController to return HTTP 201
when a comment is created: after calling commentService.create(...) and wrapping
with CommentResponse.from(...), build a ResponseEntity with status CREATED
instead of ok(). Update the method that currently returns ResponseEntity.ok(...)
so it uses ResponseEntity.status(HttpStatus.CREATED).body(...) (or
ResponseEntity.created(...) with a Location header if desired) while keeping the
same payload from CommentResponse.from(...).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/org/example/vet1177/security/SecurityConfig.java`:
- Around line 17-20: SecurityConfig currently allows all requests via
anyRequest().permitAll(), leaving CommentController endpoints
("/api/comments/**" which expect `@AuthenticationPrincipal` User) unprotected;
update SecurityConfig to remove the global permitAll and explicitly require
authentication for the comment routes (e.g. configure
authorizeHttpRequests/authorizeRequests so "/api/comments/**" -> authenticated()
and non-sensitive routes -> permitAll()), keeping CSRF/other settings as
appropriate; reference the authorizeHttpRequests call in SecurityConfig and the
CommentController path "/api/comments/**" and `@AuthenticationPrincipal` User when
making the change.

---

Duplicate comments:
In `@src/main/java/org/example/vet1177/controllers/CommentController.java`:
- Around line 30-33: The controller methods (e.g., CommentController.create)
currently inject `@AuthenticationPrincipal` User currentUser which may be null or
an incompatible principal type; change the parameter to accept
java.security.Principal or org.springframework.security.core.Authentication
(e.g., Principal principal or Authentication auth) and resolve the application
User explicitly via your user lookup (e.g.,
UserService.findByUsername(principal.getName())) with null/incompatible-type
checks; update all affected methods (the create method and the other endpoints
flagged) to validate the resolved User and throw a 401/appropriate exception
when absent instead of assuming non-null injection, and add clear error
handling/logging for incompatible principal types.

---

Nitpick comments:
In `@src/main/java/org/example/vet1177/controllers/CommentController.java`:
- Around line 34-42: Change the POST handler in CommentController to return HTTP
201 when a comment is created: after calling commentService.create(...) and
wrapping with CommentResponse.from(...), build a ResponseEntity with status
CREATED instead of ok(). Update the method that currently returns
ResponseEntity.ok(...) so it uses
ResponseEntity.status(HttpStatus.CREATED).body(...) (or
ResponseEntity.created(...) with a Location header if desired) while keeping the
same payload from CommentResponse.from(...).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 87f1ec24-7b44-4364-ad7b-3ca7886e2645

📥 Commits

Reviewing files that changed from the base of the PR and between 231cdec and 355faaa.

📒 Files selected for processing (3)
  • src/main/java/org/example/vet1177/controllers/CommentController.java
  • src/main/java/org/example/vet1177/security/SecurityConfig.java
  • src/main/java/org/example/vet1177/services/CommentService.java

Comment on lines +17 to +20
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll() // ← temporärt, öppnar allt
)

@coderabbitai coderabbitai Bot Mar 30, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify routing auth rules and principal-based controller usage are aligned.
rg -nP --type=java -C3 'anyRequest\(\)\.permitAll\(|requestMatchers\(.+\)\.authenticated\(' src/main/java/org/example/vet1177
rg -nP --type=java -C2 '@AuthenticationPrincipal\s+User\b' src/main/java/org/example/vet1177/controllers

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 3625


🏁 Script executed:

#!/bin/bash
# Check CommentController's request mapping and all endpoints
rg -nP --type=java -B5 'class CommentController|@RequestMapping|@PostMapping|@GetMapping|@PutMapping|@DeleteMapping' src/main/java/org/example/vet1177/controllers/CommentController.java | head -40

# Check if other controllers also use `@AuthenticationPrincipal`
rg -nP --type=java '@AuthenticationPrincipal\s+User\b' src/main/java/org/example/vet1177/controllers/ | grep -v CommentController

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 1000


🏁 Script executed:

#!/bin/bash
# Find all controllers in the codebase
find src/main/java/org/example/vet1177/controllers -name "*.java" -type f

# Check all controllers for authentication requirements
rg -nP --type=java '@RestController|@Controller|@RequestMapping|@AuthenticationPrincipal' src/main/java/org/example/vet1177/controllers

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 994


Do not ship with global permitAll on all routes.

Line 19 of SecurityConfig.java opens every endpoint without authentication. The CommentController endpoints (all 5 methods at /api/comments/**) require @AuthenticationPrincipal User but are currently accessible without authentication, creating a critical security gap.

🔐 Suggested hardening
 return http
         .csrf(csrf -> csrf.disable())
         .authorizeHttpRequests(auth -> auth
-                .anyRequest().permitAll()  // ← temporärt, öppnar allt
+                .requestMatchers("/api/comments/**").authenticated()
+                .anyRequest().permitAll()
         )
         .build();
📝 Committable suggestion

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

Suggested change
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.anyRequest().permitAll() // ← temporärt, öppnar allt
)
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/comments/**").authenticated()
.anyRequest().permitAll()
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/security/SecurityConfig.java` around lines
17 - 20, SecurityConfig currently allows all requests via
anyRequest().permitAll(), leaving CommentController endpoints
("/api/comments/**" which expect `@AuthenticationPrincipal` User) unprotected;
update SecurityConfig to remove the global permitAll and explicitly require
authentication for the comment routes (e.g. configure
authorizeHttpRequests/authorizeRequests so "/api/comments/**" -> authenticated()
and non-sensitive routes -> permitAll()), keeping CSRF/other settings as
appropriate; reference the authorizeHttpRequests call in SecurityConfig and the
CommentController path "/api/comments/**" and `@AuthenticationPrincipal` User when
making the change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a temporary security configuration to unblock
development and testing. Full JWT implementation with
JwtAuthFilter, stateless sessions and proper endpoint
restrictions will be added in feat/spring-security-config.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@annikaholmqvist94, understood — thanks for the context! That makes sense as a development unblocking strategy. Just a friendly reminder to ensure the feat/spring-security-config branch enforces authentication on /api/comments/** (and other protected routes) before this reaches production, since the @AuthenticationPrincipal User parameters in CommentController will silently receive null if the endpoints remain unauthenticated at that point.

Would you like me to open a follow-up issue to track the JWT/security hardening work?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes please

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh issue create \
  --repo ithsjava25/project-backend-org-random-coders \
  --title "feat: Implement JWT security hardening (JwtAuthFilter, stateless sessions, endpoint restrictions)" \
  --assignee annikaholmqvist94 \
  --body "## Summary

This issue tracks the full JWT/Spring Security implementation that will replace the temporary permissive \`SecurityConfig\` introduced in PR `#55`.

## Background

PR `#55` ([feat/comment-controller](https://github.com/ithsjava25/project-backend-org-random-coders/pull/55)) added a \`SecurityConfig\` with \`anyRequest().permitAll()\` as a temporary measure to unblock development and testing. This must be hardened before reaching production.

## Tasks

- [ ] Implement \`JwtAuthFilter\` to validate JWT tokens on incoming requests
- [ ] Configure stateless session management (\`SessionCreationPolicy.STATELESS\`)
- [ ] Restrict \`/api/comments/**\` to authenticated users only (replacing the global \`permitAll\`)
- [ ] Restrict other protected routes as appropriate
- [ ] Ensure \`@AuthenticationPrincipal User\` in \`CommentController\` receives a valid non-null principal when endpoints are called with a valid token

## References

- PR `#55` comment: https://github.com/ithsjava25/project-backend-org-random-coders/pull/55#discussion_r3009802568
- Requested by: `@annikaholmqvist94`

## Notes

Until this is implemented, the \`@AuthenticationPrincipal User\` parameters in \`CommentController\` will silently receive \`null\` for unauthenticated requests."

Length of output: 73


@annikaholmqvist94, done! I've opened issue #61 to track the JWT security hardening work:
👉 #61

It covers:

  • Implementing JwtAuthFilter
  • Configuring stateless session management
  • Restricting /api/comments/** (and other protected routes) to authenticated users
  • Ensuring @AuthenticationPrincipal User receives a valid non-null principal

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Comment Controller

1 participant