Skip to content

Conversation

@naveenpaul1
Copy link
Contributor

@naveenpaul1 naveenpaul1 commented Nov 24, 2025

Describe the Problem

  1. Bucket policy "Principal" validation was based on the email before and it updated with account/user ID
  2. put_bucket_policy validate principal account/user ID

Explain the Changes

Principal validation

  1. Validate account/user ID

S3 Rest authorize request policy

  1. Account/user ID is added to request policy validation replacing account email. account/user ID based validation for containerized deployments NSFS NC.
  2. Updated test cases(test_s3_bucket_policy.js), previousily these tests where using email for principal for both NSFS non-containerized and acontainerized, With latest changes containerized will use account/user ID and ARN. Enabled account/user ID based test cases also for containerized integration test

Testing Instructions:

  1. Create a bucket(test1) from account(account1)
  2. Put bucket policy to newly created bucket()
s3api put-bucket-policy --bucket test1 --policy '{"Version": "2012-10-17","Statement": [ { "Effect": "Allow", "Principal": { "AWS": [ "${user2_id}" ] }, "Action": [ "s3:*" ], "Resource": [ "arn:aws:s3:::test1/*", "arn:aws:s3:::test1" ] } ]}'

user2_id could be ID of different account or IAM user ID of IAM user(not belongs to account1)
3. Verify the user2 have bucket1 access.

  • Doc added/updated
  • Tests added

Summary by CodeRabbit

  • Bug Fixes

    • Refined bucket policy validation to recognize principals using multiple identification methods.
    • Enhanced account permission checks with improved principal resolution logic.
    • Added deployment-specific policy evaluation for NSFS NC configurations.
  • Tests

    • Updated bucket policy validation tests with account ID handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 24, 2025

Walkthrough

Changes refactor account/principal identity resolution across S3 bucket policy evaluation layers by normalizing account inputs to arrays in policy utilities, implementing ARN-based principal lookup in bucket server helpers, updating authorization call sites to pass principal arrays, and adjusting S3 REST endpoint routing to support NSFS NC-specific policy checks.

Changes

Cohort / File(s) Summary
Policy Evaluation Utilities
src/endpoint/s3/s3_bucket_policy_utils.js
Introduced account_arr normalization and propagated it through internal helpers (_is_principal_fit, is_statement_fit_of_method_array, _is_statements_fit) to support both string and array account inputs; updated principal matching logic to use includes for array comparison.
S3 REST Authorization
src/endpoint/s3/s3_rest.js
Modified policy check flow: account_identifier_id now always sourced from account._id; added NC-specific secondary policy check using account_identifier_name when ID-based check does not deny; adjusted ARN check trigger for containerized vs NC deployments.
Authorization Server
src/server/common_services/auth_server.js
Updated has_bucket_policy_permission call in has_bucket_action_permission to pass principal as array [ARN, account_id] instead of single ARN value.
Bucket Policy Principal Resolution
src/server/system_services/bucket_server.js
Refactored principal resolution with new helpers: introduced account_exists_by_principal_arn(principal_as_string) for ARN-based account lookup; updated get_account_by_principal(principal) to support both ARN and direct ID-based lookups; replaced inlined principal handling with composite ARN/ID resolution logic.
IAM Integration Tests
src/test/integration_tests/api/iam/test_iam_basic_integration.js
Updated after-hook to conditionally delete config_root folder only when is_nc_coretest is true; removed unconditional cleanup.
S3 Bucket Policy Tests
src/test/integration_tests/api/s3/test_s3_bucket_policy.js
Introduced account ID variables (user_a_account_id, user_b_account_id) and replaced account._id references with these variables throughout policy statements and assertions; updated Sid strings and Principal values to reflect account ID usage.
Account Utilities
src/util/account_util.js
Removed empty blank line preceding _check_if_requesting_account_is_root_account function; formatting adjustment only.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant s3_rest as s3_rest.js
    participant auth_server as auth_server.js
    participant policy_utils as s3_bucket_policy_utils.js
    participant bucket_server as bucket_server.js
    
    Client->>s3_rest: S3 Request
    s3_rest->>s3_rest: Extract account_identifier_id from account._id
    
    alt NC Deployment
        s3_rest->>auth_server: Check with account_id
        auth_server->>policy_utils: has_bucket_policy_permission<br/>[ARN, account_id]
        policy_utils->>policy_utils: Normalize to account_arr
        policy_utils->>policy_utils: Match principal via includes()
        
        alt ID Check Passed
            s3_rest->>s3_rest: Proceed
        else ID Check Not Denied
            s3_rest->>auth_server: Secondary check with<br/>account_identifier_name
            auth_server->>policy_utils: has_bucket_policy_permission<br/>[ARN, account_name]
        end
    else Containerized Deployment
        s3_rest->>auth_server: Check with account_id
        auth_server->>policy_utils: has_bucket_policy_permission<br/>[ARN, account_id]
        policy_utils->>policy_utils: Normalize to account_arr
        
        alt ARN Available
            s3_rest->>auth_server: Verify via ARN check
        end
    end
    
    auth_server->>bucket_server: get_account_by_principal()<br/>for principal validation
    bucket_server->>bucket_server: Check if ARN or ID
    bucket_server->>bucket_server: Resolve account object
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Key areas requiring extra attention:
    • bucket_server.js refactoring: Principal resolution logic now supports dual ARN/ID modes; verify both paths correctly extract and validate account information
    • s3_rest.js authorization flow: New NC-specific branching logic with secondary policy check; ensure proper state transitions and error handling between ID and name-based checks
    • s3_bucket_policy_utils.js propagation: Account parameter normalization propagates through multiple internal helpers; verify array-based principal matching (includes) maintains backward compatibility
    • auth_server.js call site: Change from single ARN to [ARN, account_id] array—ensure policy evaluation correctly handles both elements
    • Test assertions: Updated account ID variables across test_s3_bucket_policy.js; verify policy SID strings and Principal AWS values align with expected ARN/account ID formats

Possibly related PRs

Suggested reviewers

  • aayushchouhan09
  • liranmauda
  • jackyalbo

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly references the main change: updating IAM principal validation and S3 permissions to use account ID instead of email.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@pull-request-size pull-request-size bot added size/L and removed size/M labels Nov 25, 2025
@naveenpaul1 naveenpaul1 marked this pull request as ready for review November 25, 2025 14:25
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/server/system_services/bucket_server.js (2)

528-546: Consider removing unnecessary async keyword.

This function doesn't contain any await expressions. Both system_store.data.accounts.find() and system_store.get_account_by_email() appear to be synchronous operations based on usage patterns in the codebase. Marking this function async unnecessarily wraps return values in a Promise.

If this is intentional for consistency with the caller or future changes, this is fine as-is.


548-567: Function name is misleading - returns boolean, not account.

get_account_by_principal implies the function returns an account object, but it actually returns a boolean indicating whether the principal exists. Consider renaming to better reflect the return type:

  • principal_exists
  • is_valid_principal
  • validate_principal
-async function get_account_by_principal(principal) {
+async function principal_exists(principal) {

Alternatively, if a getter pattern is preferred, the function could return the account object (or undefined) and let the caller convert to boolean, which would make the validation callback cleaner and enable future use cases that need the account:

 async function get_account_by_principal(principal) {
     const principal_as_string = principal instanceof SensitiveString ? principal.unwrap() : principal;
     const is_principal_arn = principal_as_string.startsWith('arn:aws:iam::');
     if (is_principal_arn) {
-        const principal_by_arn = await account_exists_by_principal_arn(principal_as_string);
-        dbg.log3('get_account_by_principal: principal_by_arn', principal_by_arn);
-        if (principal_by_arn) return true;
+        return account_exists_by_principal_arn(principal_as_string);
     } else {
-        const account = system_store.data.accounts.find(acc => acc._id.toString() === principal_as_string);
-        const principal_by_id = account !== undefined;
-        dbg.log3('get_account_by_principal: principal_by_id', principal_by_id);
-        if (principal_by_id) return true;
+        return system_store.data.accounts.find(acc => acc._id.toString() === principal_as_string);
     }
-    return false;
 }

Then update the callback to convert to boolean:

principal => Boolean(get_account_by_principal(principal))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8204d2a and 0020baa.

📒 Files selected for processing (7)
  • src/endpoint/s3/s3_bucket_policy_utils.js (4 hunks)
  • src/endpoint/s3/s3_rest.js (2 hunks)
  • src/server/common_services/auth_server.js (1 hunks)
  • src/server/system_services/bucket_server.js (2 hunks)
  • src/test/integration_tests/api/iam/test_iam_basic_integration.js (1 hunks)
  • src/test/integration_tests/api/s3/test_s3_bucket_policy.js (10 hunks)
  • src/util/account_util.js (0 hunks)
💤 Files with no reviewable changes (1)
  • src/util/account_util.js
🧰 Additional context used
📓 Path-based instructions (1)
src/test/**/*.*

⚙️ CodeRabbit configuration file

src/test/**/*.*: Ensure that the PR includes tests for the changes.

Files:

  • src/test/integration_tests/api/iam/test_iam_basic_integration.js
  • src/test/integration_tests/api/s3/test_s3_bucket_policy.js
🧠 Learnings (6)
📓 Common learnings
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_bucket_policy_utils.js:357-368
Timestamp: 2025-11-18T07:00:17.653Z
Learning: In NooBaa codebase, account.name is always a SensitiveString instance, so calling account.name.unwrap() is safe without defensive type checks in functions like get_bucket_policy_principal_arn in src/endpoint/s3/s3_bucket_policy_utils.js.
📚 Learning: 2025-11-13T07:56:23.620Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9281
File: src/server/system_services/account_server.js:1053-1058
Timestamp: 2025-11-13T07:56:23.620Z
Learning: In noobaa-core, account_server.js is only used in containerized deployments, not in NSFS/NC deployments. NSFS/NC deployments have separate account management code in src/manage_nsfs/ directory. Therefore, account_server.js only processes accounts from account_schema.js where owner is an objectid reference, never from nsfs_account_schema.js where owner is a string.

Applied to files:

  • src/endpoint/s3/s3_rest.js
  • src/test/integration_tests/api/s3/test_s3_bucket_policy.js
📚 Learning: 2025-11-12T04:55:42.193Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_rest.js:258-261
Timestamp: 2025-11-12T04:55:42.193Z
Learning: In the context of S3 REST requests (src/endpoint/s3/s3_rest.js), the account.owner field from req.object_sdk.requesting_account is already a string (account ID) because it comes from RPC serialization where owner._id.toString() is applied in account_server.js. No additional .toString() or ._id extraction is needed when passing account.owner to IAM utility functions.

Applied to files:

  • src/endpoint/s3/s3_rest.js
  • src/test/integration_tests/api/s3/test_s3_bucket_policy.js
  • src/endpoint/s3/s3_bucket_policy_utils.js
📚 Learning: 2025-11-18T07:00:17.653Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9277
File: src/endpoint/s3/s3_bucket_policy_utils.js:357-368
Timestamp: 2025-11-18T07:00:17.653Z
Learning: In NooBaa codebase, account.name is always a SensitiveString instance, so calling account.name.unwrap() is safe without defensive type checks in functions like get_bucket_policy_principal_arn in src/endpoint/s3/s3_bucket_policy_utils.js.

Applied to files:

  • src/endpoint/s3/s3_rest.js
  • src/server/common_services/auth_server.js
  • src/test/integration_tests/api/s3/test_s3_bucket_policy.js
  • src/endpoint/s3/s3_bucket_policy_utils.js
  • src/server/system_services/bucket_server.js
📚 Learning: 2025-11-19T15:03:42.260Z
Learnt from: shirady
Repo: noobaa/noobaa-core PR: 9291
File: src/server/common_services/auth_server.js:548-554
Timestamp: 2025-11-19T15:03:42.260Z
Learning: In src/server/common_services/auth_server.js, account objects are loaded directly from system_store (e.g., system_store.data.get_by_id()), so account.owner is an object ID reference with an ._id property, not a string. This differs from s3_rest.js where account.owner is a string due to RPC serialization.

Applied to files:

  • src/endpoint/s3/s3_rest.js
  • src/test/integration_tests/api/s3/test_s3_bucket_policy.js
  • src/server/system_services/bucket_server.js
📚 Learning: 2025-08-08T13:08:38.361Z
Learnt from: naveenpaul1
Repo: noobaa/noobaa-core PR: 9182
File: src/server/system_services/bucket_server.js:1324-1327
Timestamp: 2025-08-08T13:08:38.361Z
Learning: In src/server/system_services/bucket_server.js, the update_all_buckets_default_pool(req) handler expects req.rpc_params.pool_name to be a plain string (not a SensitiveString wrapper), so calling .unwrap() is not needed there.

Applied to files:

  • src/server/system_services/bucket_server.js
🧬 Code graph analysis (6)
src/endpoint/s3/s3_rest.js (1)
src/endpoint/s3/s3_bucket_policy_utils.js (1)
  • account (303-303)
src/server/common_services/auth_server.js (3)
src/endpoint/s3/s3_bucket_policy_utils.js (1)
  • account (303-303)
src/endpoint/s3/s3_rest.js (2)
  • account (252-252)
  • account (343-343)
src/server/system_services/bucket_server.js (1)
  • account (561-561)
src/test/integration_tests/api/iam/test_iam_basic_integration.js (1)
src/test/system_tests/test_utils.js (1)
  • is_nc_coretest (48-48)
src/test/integration_tests/api/s3/test_s3_bucket_policy.js (2)
src/test/system_tests/test_utils.js (1)
  • is_nc_coretest (48-48)
src/endpoint/s3/s3_bucket_policy_utils.js (2)
  • account (303-303)
  • _ (4-4)
src/endpoint/s3/s3_bucket_policy_utils.js (1)
src/endpoint/iam/iam_utils.js (1)
  • statement_principal (723-723)
src/server/system_services/bucket_server.js (6)
src/server/system_services/account_server.js (11)
  • SensitiveString (15-15)
  • dbg (12-12)
  • account (69-69)
  • account (117-117)
  • account (135-137)
  • account (159-159)
  • account (207-207)
  • account (330-330)
  • account (693-693)
  • account (957-957)
  • system_store (17-17)
src/api/account_api.js (1)
  • SensitiveString (4-4)
src/cmd/manage_nsfs.js (1)
  • SensitiveString (25-25)
src/api/common_api.js (1)
  • SensitiveString (4-4)
src/cmd/nsfs.js (1)
  • SensitiveString (38-38)
src/sdk/bucketspace_nb.js (1)
  • dbg (7-7)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Noobaa Image
  • GitHub Check: run-jest-unit-tests
  • GitHub Check: run-package-lock-validation
🔇 Additional comments (14)
src/test/integration_tests/api/iam/test_iam_basic_integration.js (1)

76-78: LGTM!

The conditional cleanup correctly ensures folder_delete only runs when is_nc_coretest is true, matching the condition under which config_root is set in the before hook. This prevents attempting to delete an undefined path in containerized deployments.

src/server/common_services/auth_server.js (1)

558-566: LGTM!

The change to pass [arn, account._id.toString()] as an array aligns with the updated has_bucket_policy_permission signature that now accepts an array of account identifiers. This enables policy principal matching against both the ARN and the account ID, supporting the PR's objective of ID-based validation.

src/endpoint/s3/s3_rest.js (3)

255-257: LGTM!

The simplification to always source account_identifier_id from account._id is correct. Both NC and containerized deployments now validate bucket policies against the account ID, aligning with the PR's objective of ID-based principal validation.


313-320: LGTM!

The name-based permission check is now correctly scoped to NSFS NC deployments only, and restricted to root accounts (account.owner === undefined). This maintains backward compatibility for NC while preventing IAM users from matching by name.


322-330: LGTM!

The ARN-based permission check is now explicitly limited to containerized deployments (!is_nc_deployment). This correctly separates the authorization paths: NC uses ID + name, while containerized uses ID + ARN.

src/endpoint/s3/s3_bucket_policy_utils.js (3)

153-168: LGTM!

The JSDoc update and account_arr normalization correctly document the function's ability to accept either a string or an array of account identifiers. The normalization pattern Array.isArray(account) ? account : [account] ensures consistent array handling downstream.


204-222: LGTM!

The refactored _is_principal_fit function correctly uses account_arr.includes(principal.unwrap()) for matching, allowing a principal to match any identifier in the array (ID, ARN, or name). The wildcard check principal.unwrap() === '*' is evaluated first, maintaining correct anonymous access handling.


239-251: LGTM!

The signature changes to is_statement_fit_of_method_array and _is_statements_fit correctly propagate account_arr through the call chain, ensuring consistent array-based principal matching throughout the policy evaluation flow.

src/test/integration_tests/api/s3/test_s3_bucket_policy.js (5)

68-70: LGTM!

The addition of user_a_account_id and user_b_account_id variables provides a consistent way to reference account IDs across tests, abstracting the difference between NC (_id) and containerized (id) response formats.


127-134: LGTM!

The account ID extraction correctly handles the different response formats: NC deployments use _id while containerized deployments use id. The added console logging will aid debugging.


156-157: LGTM!

The principal construction correctly differentiates between NC (account name) and containerized (ARN from account ID) deployments, aligning with how each deployment validates principals.


315-362: LGTM!

The test cases for principal by account ID correctly use user_a_account_id in both the policy Sid and Principal AWS fields, properly testing ID-based authorization for both NC and containerized deployments.


482-484: Tests enabled for both deployment types.

The removal of this.skip() guards for NC-only tests (// if (!is_nc_coretest) this.skip();) enables these account-ID-based policy tests to run on both NC and containerized deployments. This aligns with the PR goal of enabling ID-based validation across deployment types.

Also applies to: 517-519, 583-585

src/server/system_services/bucket_server.js (1)

572-573: No issues found - async callback handling is correct.

The callback is properly awaited by validate_s3_policy at line 303 of s3_bucket_policy_utils.js: const account = await get_account_handler(principal);. The Promise returned by get_account_by_principal is correctly handled.

}
// Losing this value in-between, assigning it again
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(account_info_a._id.toString());
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(user_b_account_id.toString());
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Bug: a_principal is constructed using user_b_account_id instead of user_a.

For containerized deployments, a_principal is being set with user_b_account_id, which is incorrect. This will cause the deny_account_by_name_all_s3_actions_statement to target user_b instead of user_a in containerized tests.

Apply this diff to fix the bug:

-        a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(user_b_account_id.toString());
+        a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(user_a_account_id.toString());
📝 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
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(user_b_account_id.toString());
a_principal = is_nc_coretest ? user_a : s3_bucket_policy_utils.create_arn_for_root(user_a_account_id.toString());
🤖 Prompt for AI Agents
In src/test/integration_tests/api/s3/test_s3_bucket_policy.js around line 397,
the code constructs a_principal using user_b_account_id when it should use
user_a's account id for containerized deployments; update the ternary fallback
to use s3_bucket_policy_utils.create_arn_for_root(user_a_account_id.toString())
instead of user_b_account_id so the
deny_account_by_name_all_s3_actions_statement targets user_a as intended.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant