Skip to content

Conversation

@KevLehman
Copy link
Member

@KevLehman KevLehman commented Nov 17, 2025

Proposed changes (including videos or screenshots)

Issue(s)

https://rocketchat.atlassian.net/browse/ABAC-12

Steps to test or reproduce

Further comments

Summary by CodeRabbit

Release Notes

  • New Features
    • Added new API endpoint for synchronizing user ABAC (Attribute-Based Access Control) attributes via LDAP integration, enabling batch user attribute updates.
    • Enhanced user lookup capabilities to support finding users by multiple identifier types (usernames, user IDs, emails, or LDAP IDs) in a single query.

@changeset-bot
Copy link

changeset-bot bot commented Nov 17, 2025

⚠️ No Changeset found

Latest commit: 72caa83

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Nov 17, 2025

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 17, 2025

Walkthrough

This PR implements a new API endpoint POST /api/v1/abac/users/sync that allows manual triggering of LDAP user attribute synchronization for ABAC enforcement. It adds request validation, LDAP sync logic, and a multi-identifier user lookup utility across the API, LDAP manager, service layer, and data models.

Changes

Cohort / File(s) Summary
API Endpoint & Validation
apps/meteor/ee/server/api/abac/index.ts, apps/meteor/ee/server/api/abac/schemas.ts
New POST endpoint abac/users/sync with license/permission checks; validates request payload with POSTAbacUsersSyncBodySchema supporting optional arrays (usernames, ids, emails, ldapIds) with at-least-one requirement.
LDAP Synchronization Logic
apps/meteor/ee/server/lib/ldap/Manager.ts, apps/meteor/ee/server/local-services/ldap/service.ts
Adds syncUsersAbacAttributes() public method in LDAPEEService delegating to LDAPEEManager; Manager implements iteration over users, ABAC guard checks, LDAP connection management, and per-user attribute sync via helper syncUserAbacAttribute().
Type & Interface Definitions
apps/meteor/ee/server/sdk/types/ILDAPEEService.ts
Extends ILDAPEEService interface with new syncUsersAbacAttributes() method signature.
Data Access Layer
packages/model-typings/src/models/IUsersModel.ts, packages/models/src/models/Users.ts
Adds findUsersByIdentifiers() method supporting multi-criteria lookup (usernames, ids, emails, ldapIds) returning active users as a FindCursor.

Sequence Diagram(s)

sequenceDiagram
    actor Admin
    participant Endpoint as POST abac/users/sync
    participant Validator as Request Validator
    participant Manager as LDAPEEManager
    participant UserModel as Users Model
    participant LDAP as LDAP Connection
    participant Abac as ABAC Module
    
    Admin->>Endpoint: POST with identifiers
    Endpoint->>Validator: Validate license & permission
    Validator-->>Endpoint: ✓ Valid
    Endpoint->>Validator: Validate payload schema
    Validator-->>Endpoint: ✓ Schema valid
    Endpoint->>UserModel: findUsersByIdentifiers(params)
    UserModel-->>Endpoint: FindCursor<IUser>
    Endpoint->>Manager: syncUsersAbacAttributes(cursor)
    loop For each user
        Manager->>LDAP: Resolve LDAP user attributes
        LDAP-->>Manager: User attributes
        Manager->>Abac: addSubjectAttributes(user, attributes)
        Abac-->>Manager: ✓ Synced
    end
    Manager-->>Endpoint: ✓ Sync complete
    Endpoint-->>Admin: 200 Success response
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Straightforward new feature with clear separation of concerns across layers (API → Manager → LDAP)
  • Logic is localized and follows existing patterns (service delegation, ABAC guards)
  • Main complexity points:
    • LDAP attribute map validation and per-user sync logic in Manager
    • Multi-identifier query construction in Users model (ensure $or query handles all cases correctly)

Possibly related PRs

Suggested reviewers

  • tassoevan
  • MartinSchoeler

Poem

🐰 Hops with glee 🏃‍♂️
A sync endpoint blooms,
Users dance through LDAP rooms,
Attributes aligned with care,
ABAC rules, fresh and fair! ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The implementation adds the required POST /api/v1/abac/users/sync endpoint with license/permission checks, payload validation, user lookup, and LDAP sync triggering. Multi-identifier support (Option A) is implemented. However, security logging is not evident in the provided changes. Verify that security logging for force-sync actions is implemented, capturing actor, synced users, and timestamp as required by ABAC-12 acceptance criteria.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Force LDAP sync for specific users via endpoint' clearly and concisely summarizes the main change—adding an endpoint to force LDAP synchronization for users.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the ABAC-12 endpoint: new endpoint, schemas, LDAP sync methods, and user lookup utility. No extraneous modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/ldap-sync-force

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


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.

@codecov
Copy link

codecov bot commented Nov 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (feat/abac@a361681). Learn more about missing BASE report.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##             feat/abac   #37542   +/-   ##
============================================
  Coverage             ?   54.50%           
============================================
  Files                ?     2659           
  Lines                ?    49968           
  Branches             ?    11125           
============================================
  Hits                 ?    27236           
  Misses               ?    20591           
  Partials             ?     2141           
Flag Coverage Δ
e2e 57.44% <ø> (?)
e2e-api 43.86% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@KevLehman KevLehman force-pushed the feat/ldap-sync-force branch from c06191e to 72caa83 Compare November 18, 2025 18:16
@github-actions
Copy link
Contributor

📦 Docker Image Size Report

📈 Changes

Service Current Baseline Change Percent
sum of all images 1.2GiB 1.2GiB +12MiB
rocketchat 367MiB 355MiB +12MiB
omnichannel-transcript-service 141MiB 141MiB +11KiB
queue-worker-service 141MiB 141MiB +12KiB
ddp-streamer-service 127MiB 127MiB +8.4KiB
account-service 114MiB 114MiB +11KiB
authorization-service 111MiB 111MiB +36KiB
stream-hub-service 111MiB 111MiB +7.7KiB
presence-service 111MiB 111MiB +9.4KiB

📊 Historical Trend

---
config:
  theme: "dark"
  xyChart:
    width: 900
    height: 400
---
xychart
  title "Image Size Evolution by Service (Last 30 Days + This PR)"
  x-axis ["11/15 22:28", "11/16 01:28", "11/17 23:50", "11/18 22:53", "11/19 03:03 (PR)"]
  y-axis "Size (GB)" 0 --> 0.5
  line "account-service" [0.11, 0.11, 0.11, 0.11, 0.11]
  line "authorization-service" [0.11, 0.11, 0.11, 0.11, 0.11]
  line "ddp-streamer-service" [0.12, 0.12, 0.12, 0.12, 0.12]
  line "omnichannel-transcript-service" [0.14, 0.14, 0.14, 0.14, 0.14]
  line "presence-service" [0.11, 0.11, 0.11, 0.11, 0.11]
  line "queue-worker-service" [0.14, 0.14, 0.14, 0.14, 0.14]
  line "rocketchat" [0.36, 0.36, 0.35, 0.35, 0.36]
  line "stream-hub-service" [0.11, 0.11, 0.11, 0.11, 0.11]
Loading

Statistics (last 4 days):

  • 📊 Average: 1.4GiB
  • ⬇️ Minimum: 1.2GiB
  • ⬆️ Maximum: 1.6GiB
  • 🎯 Current PR: 1.2GiB
ℹ️ About this report

This report compares Docker image sizes from this build against the develop baseline.

  • Tag: pr-37542
  • Baseline: develop
  • Timestamp: 2025-11-19 03:03:54 UTC
  • Historical data points: 4

Updated: Wed, 19 Nov 2025 03:03:55 GMT

@KevLehman KevLehman marked this pull request as ready for review November 19, 2025 14:46
@KevLehman KevLehman requested a review from a team as a code owner November 19, 2025 14:46
Copy link
Contributor

@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)
apps/meteor/ee/server/lib/ldap/Manager.ts (1)

131-150: Consider adding sync result feedback and improving error handling.

The current implementation catches and logs errors but provides no feedback to the caller about which users succeeded or failed. For a user-triggered sync operation via the API, this makes troubleshooting difficult.

Consider collecting and returning sync results:

public static async syncUsersAbacAttributes(users: FindCursor<IUser>): Promise<{ succeeded: string[]; failed: Array<{ userId: string; error: string }> }> {
	if (!settings.get('LDAP_Enable') || !License.hasModule('abac') || !settings.get('ABAC_Enabled')) {
		return { succeeded: [], failed: [] };
	}

	const succeeded: string[] = [];
	const failed: Array<{ userId: string; error: string }> = [];

	try {
		const ldap = new LDAPConnection();
		await ldap.connect();

		try {
			for await (const user of users) {
				try {
					await this.syncUserAbacAttribute(ldap, user);
					succeeded.push(user._id);
				} catch (error) {
					failed.push({ userId: user._id, error: String(error) });
					logger.error({ msg: 'Failed to sync ABAC attributes for user', userId: user._id, error });
				}
			}
		} finally {
			ldap.disconnect();
		}
	} catch (error) {
		logger.error(error);
		throw error;
	}

	return { succeeded, failed };
}

This would require updating the interface signature and the API endpoint to return meaningful feedback.

apps/meteor/ee/server/api/abac/index.ts (1)

182-207: Consider providing sync operation feedback.

The endpoint returns a simple success response regardless of whether any users were found or if the sync operation succeeded or failed. For an admin-triggered operation, providing feedback about the operation result would improve usability and troubleshooting.

Consider returning operation statistics:

 .post(
 	'abac/users/sync',
 	{
 		authRequired: true,
 		permissionsRequired: ['abac-management'],
 		license: ['abac', 'ldap-enterprise'],
 		body: POSTAbacUsersSyncBodySchema,
 		response: {
-			200: GenericSuccessSchema,
+			200: ajv.compile<{ success: true; usersProcessed: number }>({ 
+				type: 'object', 
+				properties: { 
+					success: { type: 'boolean', enum: [true] }, 
+					usersProcessed: { type: 'number' } 
+				},
+				required: ['success', 'usersProcessed']
+			}),
 		},
 	},
 	async function action() {
 		if (!settings.get('ABAC_Enabled')) {
 			throw new Error('error-abac-not-enabled');
 		}
 
 		const { usernames, ids, emails, ldapIds } = this.bodyParams;
 
-		await LDAPEE.syncUsersAbacAttributes(Users.findUsersByIdentifiers({ usernames, ids, emails, ldapIds }));
+		const usersCursor = Users.findUsersByIdentifiers({ usernames, ids, emails, ldapIds });
+		const usersProcessed = await usersCursor.count();
+		
+		if (usersProcessed === 0) {
+			throw new Error('error-no-users-found');
+		}
+		
+		await LDAPEE.syncUsersAbacAttributes(Users.findUsersByIdentifiers({ usernames, ids, emails, ldapIds }));
 
-		return API.v1.success();
+		return API.v1.success({ usersProcessed });
 	},
 )

Note: This assumes the LDAPEEService signature remains unchanged. For better feedback, consider also updating the service layer to return sync results as suggested in the Manager.ts review.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a361681 and 72caa83.

📒 Files selected for processing (7)
  • apps/meteor/ee/server/api/abac/index.ts (4 hunks)
  • apps/meteor/ee/server/api/abac/schemas.ts (1 hunks)
  • apps/meteor/ee/server/lib/ldap/Manager.ts (3 hunks)
  • apps/meteor/ee/server/local-services/ldap/service.ts (2 hunks)
  • apps/meteor/ee/server/sdk/types/ILDAPEEService.ts (1 hunks)
  • packages/model-typings/src/models/IUsersModel.ts (1 hunks)
  • packages/models/src/models/Users.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-24T17:32:05.348Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37299
File: apps/meteor/ee/server/lib/ldap/Manager.ts:438-454
Timestamp: 2025-10-24T17:32:05.348Z
Learning: In Rocket.Chat, ABAC attributes can only be set on private rooms and teams (type 'p'), not on public rooms (type 'c'). Therefore, when checking for ABAC-protected rooms/teams during LDAP sync or similar operations, it's sufficient to query only private rooms using methods like `findPrivateRoomsByIdsWithAbacAttributes`.

Applied to files:

  • apps/meteor/ee/server/local-services/ldap/service.ts
  • apps/meteor/ee/server/lib/ldap/Manager.ts
📚 Learning: 2025-11-07T14:50:33.544Z
Learnt from: KevLehman
Repo: RocketChat/Rocket.Chat PR: 37423
File: packages/i18n/src/locales/en.i18n.json:18-18
Timestamp: 2025-11-07T14:50:33.544Z
Learning: Rocket.Chat settings: in apps/meteor/ee/server/settings/abac.ts, the Abac_Cache_Decision_Time_Seconds setting uses invalidValue: 0 as the fallback when ABAC is unlicensed. With a valid license, admins can still set the value to 0 to intentionally disable the ABAC decision cache.

Applied to files:

  • apps/meteor/ee/server/api/abac/index.ts
🧬 Code graph analysis (6)
apps/meteor/ee/server/sdk/types/ILDAPEEService.ts (1)
packages/core-typings/src/IUser.ts (1)
  • IUser (187-258)
packages/model-typings/src/models/IUsersModel.ts (1)
packages/core-typings/src/IUser.ts (1)
  • IUser (187-258)
apps/meteor/ee/server/local-services/ldap/service.ts (1)
packages/core-typings/src/IUser.ts (1)
  • IUser (187-258)
apps/meteor/ee/server/lib/ldap/Manager.ts (2)
packages/core-typings/src/IUser.ts (1)
  • IUser (187-258)
packages/core-services/src/index.ts (2)
  • License (164-164)
  • Abac (202-202)
packages/models/src/models/Users.ts (1)
packages/core-typings/src/IUser.ts (1)
  • IUser (187-258)
apps/meteor/ee/server/api/abac/index.ts (2)
apps/meteor/ee/server/api/abac/schemas.ts (3)
  • POSTAbacUsersSyncBodySchema (252-257)
  • GenericSuccessSchema (17-17)
  • GenericErrorSchema (259-259)
packages/rest-typings/src/v1/Ajv.ts (1)
  • validateUnauthorizedErrorResponse (70-70)
🔇 Additional comments (5)
packages/model-typings/src/models/IUsersModel.ts (1)

94-97: LGTM!

The interface definition correctly matches the implementation and is well-positioned in the file.

apps/meteor/ee/server/api/abac/schemas.ts (1)

220-257: LGTM!

The schema validation is well-structured and correctly enforces the requirement that at least one identifier array must be provided (via anyOf), while ensuring arrays are non-empty (minItems: 1) and contain valid identifiers (minLength: 1, uniqueItems: true).

apps/meteor/ee/server/sdk/types/ILDAPEEService.ts (1)

1-10: LGTM!

The interface extension correctly adds the new method signature with proper imports. The method signature is consistent with the implementation in the service and manager layers.

apps/meteor/ee/server/lib/ldap/Manager.ts (1)

758-771: LGTM!

The single-user sync implementation correctly reuses the existing findLDAPUser helper and delegates to Abac.addSubjectAttributes. The error handling and early returns are appropriate for this context.

apps/meteor/ee/server/local-services/ldap/service.ts (1)

27-29: LGTM!

The service method correctly delegates to the manager implementation and follows the established pattern used by other sync methods in this class.

@tassoevan tassoevan merged commit 9a6b62f into feat/abac Nov 19, 2025
155 of 165 checks passed
@tassoevan tassoevan deleted the feat/ldap-sync-force branch November 19, 2025 17:26
@coderabbitai coderabbitai bot mentioned this pull request Nov 28, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants