BLOG-119 Restricted access to unpublished posts #124

Merged
squid merged 3 commits from BLOG-119_restrict_unpublished_post_access into main 2025-08-06 22:13:55 +08:00
Owner

Description

This PR introduces an authorization layer for the post feature. It ensures that create, update, and read operations for posts are properly controlled based on user authentication status and post visibility (published vs. unpublished).

Key Changes:

  • Restricted Access to Unpublished Posts:

    • Unauthenticated users can no longer access unpublished posts via the GET /post/{id} endpoint. Attempting to do so will now result in an HTTP 401 Unauthorized error.
    • The get_all_post_info endpoint is now aware of the user's authentication status to correctly filter posts.
  • Authentication Required for Modifications:

    • Creating (POST /post) and updating (PUT /post/{id}) posts now requires an authenticated user. The user_id is passed from the web handler through the controller to the use cases.
  • New Error Type:

    • A new PostError::Unauthorized variant has been added to handle access control failures gracefully.
  • API & Core Logic Updates:

    • The PostController, use cases (GetFullPostUseCase, GetAllPostInfoUseCase, etc.), and web handlers have been updated to accept and process the user_id.
    • The GetFullPostUseCase now contains the primary logic to prevent unauthenticated access to draft posts.
    • OpenAPI (Utopia) documentation has been updated to reflect these new authorization rules.

Package Changes

No response

Screenshots

No response

Reference

Resolves #119

Checklist

  • A milestone is set
  • The related issuse has been linked to this branch
### Description This PR introduces an authorization layer for the post feature. It ensures that create, update, and read operations for posts are properly controlled based on user authentication status and post visibility (published vs. unpublished). #### Key Changes: * **Restricted Access to Unpublished Posts**: * Unauthenticated users can no longer access unpublished posts via the `GET /post/{id}` endpoint. Attempting to do so will now result in an `HTTP 401 Unauthorized` error. * The `get_all_post_info` endpoint is now aware of the user's authentication status to correctly filter posts. * **Authentication Required for Modifications**: * Creating (`POST /post`) and updating (`PUT /post/{id}`) posts now requires an authenticated user. The `user_id` is passed from the web handler through the controller to the use cases. * **New Error Type**: * A new `PostError::Unauthorized` variant has been added to handle access control failures gracefully. * **API & Core Logic Updates**: * The `PostController`, use cases (`GetFullPostUseCase`, `GetAllPostInfoUseCase`, etc.), and web handlers have been updated to accept and process the `user_id`. * The `GetFullPostUseCase` now contains the primary logic to prevent unauthenticated access to draft posts. * OpenAPI (Utopia) documentation has been updated to reflect these new authorization rules. ### Package Changes _No response_ ### Screenshots _No response_ ### Reference Resolves #119 ### Checklist - [x] A milestone is set - [x] The related issuse has been linked to this branch
squid added this to the 0.3 milestone 2025-08-06 22:07:20 +08:00
squid added 2 commits 2025-08-06 22:07:20 +08:00
BLOG-119 feat: add user_id parameter to get_all_post_info and get_post_by_id handlers for enhanced access control
All checks were successful
Frontend CI / build (push) Successful in 1m41s
PR Title Check / pr-title-check (pull_request) Successful in 13s
Auto Comment On PR / add_improve_comment (pull_request) Successful in 16s
1f25fad44a
Collaborator

/improve

/improve
Collaborator

PR Code Suggestions

CategorySuggestion                                                                                                                                    Impact
Security
Correct post visibility for users

The current logic for is_published_only is flawed. If user_id is present, it
incorrectly forces is_published_only to true, preventing authenticated users from
seeing their own unpublished posts. More critically, if is_published_only is false
and user_id is None, this line would allow unauthenticated users to view unpublished
posts, which is a security vulnerability. The is_published_only flag passed to the
repository should be true for unauthenticated users, and retain its original value
for authenticated users.

backend/feature/post/src/application/use_case/get_all_post_info_use_case.rs [36]

-let is_published_only = is_published_only || user_id.is_some();
+let is_published_only = if user_id.is_none() {
+    true
+} else {
+    is_published_only
+};
Suggestion importance[1-10]: 10

__

Why: The suggestion correctly identifies a security vulnerability where unauthenticated users could potentially view unpublished posts. The proposed improved_code accurately fixes this by ensuring is_published_only is true for unauthenticated users, while allowing authenticated users to see their own unpublished posts.

High
Verify post ownership for access

The current check only prevents unauthenticated users from viewing unpublished
posts. However, it does not verify if an authenticated user (user_id.is_some()) is
the author of an unpublished post. An authenticated user should only be able to
view their own unpublished posts, not any unpublished post. Add a check to ensure
user_id matches post.author_id when the post is unpublished and user_id is present.

backend/feature/post/src/application/use_case/get_full_post_use_case.rs [30-32]

-if post.info.published_time.is_none() && user_id.is_none() {
-    return Err(PostError::Unauthorized);
+if post.info.published_time.is_none() {
+    if user_id.is_none() || user_id != Some(post.author_id) {
+        return Err(PostError::Unauthorized);
+    }
 }
Suggestion importance[1-10]: 10

__

Why: This suggestion points out a critical security flaw where any authenticated user could view any unpublished post. The improved_code correctly adds a check to ensure that if a post is unpublished, only its author (or an unauthenticated user, who would be denied) can access it, preventing unauthorized access.

High
## PR Code Suggestions ✨ <!-- --> <table><thead><tr><td><strong>Category</strong></td><td align=left><strong>Suggestion&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </strong></td><td align=center><strong>Impact</strong></td></tr><tbody><tr><td rowspan=2>Security</td> <td> <details><summary>Correct post visibility for users</summary> ___ **The current logic for <code>is_published_only</code> is flawed. If <code>user_id</code> is present, it <br>incorrectly forces <code>is_published_only</code> to <code>true</code>, preventing authenticated users from <br>seeing their own unpublished posts. More critically, if <code>is_published_only</code> is <code>false</code> <br>and <code>user_id</code> is <code>None</code>, this line would allow unauthenticated users to view unpublished <br>posts, which is a security vulnerability. The <code>is_published_only</code> flag passed to the <br>repository should be <code>true</code> for unauthenticated users, and retain its original value <br>for authenticated users.** [backend/feature/post/src/application/use_case/get_all_post_info_use_case.rs [36]](https://git.squidspirit.com/squid/blog/src/branch/BLOG-119_restrict_unpublished_post_access/backend/feature/post/src/application/use_case/get_all_post_info_use_case.rs#L36-L36) ```diff -let is_published_only = is_published_only || user_id.is_some(); +let is_published_only = if user_id.is_none() { + true +} else { + is_published_only +}; ``` <details><summary>Suggestion importance[1-10]: 10</summary> __ Why: The suggestion correctly identifies a security vulnerability where unauthenticated users could potentially view unpublished posts. The proposed `improved_code` accurately fixes this by ensuring `is_published_only` is `true` for unauthenticated users, while allowing authenticated users to see their own unpublished posts. </details></details></td><td align=center>High </td></tr><tr><td> <details><summary>Verify post ownership for access</summary> ___ **The current check only prevents unauthenticated users from viewing unpublished <br>posts. However, it does not verify if an authenticated user (<code>user_id.is_some()</code>) is <br>the *author* of an unpublished post. An authenticated user should only be able to <br>view *their own* unpublished posts, not any unpublished post. Add a check to ensure <br><code>user_id</code> matches <code>post.author_id</code> when the post is unpublished and <code>user_id</code> is present.** [backend/feature/post/src/application/use_case/get_full_post_use_case.rs [30-32]](https://git.squidspirit.com/squid/blog/src/branch/BLOG-119_restrict_unpublished_post_access/backend/feature/post/src/application/use_case/get_full_post_use_case.rs#L30-L32) ```diff -if post.info.published_time.is_none() && user_id.is_none() { - return Err(PostError::Unauthorized); +if post.info.published_time.is_none() { + if user_id.is_none() || user_id != Some(post.author_id) { + return Err(PostError::Unauthorized); + } } ``` <details><summary>Suggestion importance[1-10]: 10</summary> __ Why: This suggestion points out a critical security flaw where any authenticated user could view any unpublished post. The `improved_code` correctly adds a check to ensure that if a post is unpublished, only its author (or an unauthenticated user, who would be denied) can access it, preventing unauthorized access. </details></details></td><td align=center>High </td></tr></tr></tbody></table>
squid added 1 commit 2025-08-06 22:11:30 +08:00
BLOG-119 fix: correct logic for is_published_only in get_all_post_info execution based on user_id presence
All checks were successful
PR Title Check / pr-title-check (pull_request) Successful in 14s
Frontend CI / build (push) Successful in 1m18s
50c9234fc3
Author
Owner

The current logic for is_published_only is flawed. If user_id is present, it
incorrectly forces is_published_only to true, preventing authenticated users from
seeing their own unpublished posts. More critically, if is_published_only is false
and user_id is None, this line would allow unauthenticated users to view unpublished
posts, which is a security vulnerability. The is_published_only flag passed to the
repository should be true for unauthenticated users, and retain its original value
for authenticated users.

backend/feature/post/src/application/use_case/get_all_post_info_use_case.rs [36]

-let is_published_only = is_published_only || user_id.is_some();
+let is_published_only = if user_id.is_none() {
+    true
+} else {
+    is_published_only
+};

Addressed in 50c9234fc3.

> **The current logic for <code>is_published_only</code> is flawed. If <code>user_id</code> is present, it <br>incorrectly forces <code>is_published_only</code> to <code>true</code>, preventing authenticated users from <br>seeing their own unpublished posts. More critically, if <code>is_published_only</code> is <code>false</code> <br>and <code>user_id</code> is <code>None</code>, this line would allow unauthenticated users to view unpublished <br>posts, which is a security vulnerability. The <code>is_published_only</code> flag passed to the <br>repository should be <code>true</code> for unauthenticated users, and retain its original value <br>for authenticated users.** > > [backend/feature/post/src/application/use_case/get_all_post_info_use_case.rs [36]](https://git.squidspirit.com/squid/blog/src/branch/BLOG-119_restrict_unpublished_post_access/backend/feature/post/src/application/use_case/get_all_post_info_use_case.rs#L36-L36) > > ```diff > -let is_published_only = is_published_only || user_id.is_some(); > +let is_published_only = if user_id.is_none() { > + true > +} else { > + is_published_only > +}; > ``` Addressed in https://git.squidspirit.com/squid/blog/commit/50c9234fc339b1c6ef52f8cd56c6e82c50215784.
Author
Owner

The current check only prevents unauthenticated users from viewing unpublished
posts. However, it does not verify if an authenticated user (user_id.is_some()) is
the author of an unpublished post. An authenticated user should only be able to
view their own unpublished posts, not any unpublished post. Add a check to ensure
user_id matches post.author_id when the post is unpublished and user_id is present.

backend/feature/post/src/application/use_case/get_full_post_use_case.rs [30-32]

-if post.info.published_time.is_none() && user_id.is_none() {
-    return Err(PostError::Unauthorized);
+if post.info.published_time.is_none() {
+    if user_id.is_none() || user_id != Some(post.author_id) {
+        return Err(PostError::Unauthorized);
+    }
 }

The author hasn't been implemented.

> **The current check only prevents unauthenticated users from viewing unpublished <br>posts. However, it does not verify if an authenticated user (<code>user_id.is_some()</code>) is <br>the *author* of an unpublished post. An authenticated user should only be able to <br>view *their own* unpublished posts, not any unpublished post. Add a check to ensure <br><code>user_id</code> matches <code>post.author_id</code> when the post is unpublished and <code>user_id</code> is present.** > > [backend/feature/post/src/application/use_case/get_full_post_use_case.rs [30-32]](https://git.squidspirit.com/squid/blog/src/branch/BLOG-119_restrict_unpublished_post_access/backend/feature/post/src/application/use_case/get_full_post_use_case.rs#L30-L32) > > ```diff > -if post.info.published_time.is_none() && user_id.is_none() { > - return Err(PostError::Unauthorized); > +if post.info.published_time.is_none() { > + if user_id.is_none() || user_id != Some(post.author_id) { > + return Err(PostError::Unauthorized); > + } > } > ``` The author hasn't been implemented.
squid merged commit e6b41a768f into main 2025-08-06 22:13:55 +08:00
squid deleted branch BLOG-119_restrict_unpublished_post_access 2025-08-06 22:13:55 +08:00
Sign in to join this conversation.
No description provided.