Skip to content

Conversation

@SailReal
Copy link
Member

@SailReal SailReal commented Mar 26, 2025

Update Flow for existing deployments:

cat << 'EOF' > partial-realm-import.json
{
	"users":[
		{
			"username": "system",
			"email": "system@localhost",
			"enabled": true,
			"serviceAccountClientId": "cryptomatorhub-system",
			"clientRoles" : {
				 "realm-management" : [ "realm-admin" ]
			 },
			"attributes": {
				 "picture": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiMwMDAiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj4KCTxtYXNrIGlkPSJjbGlwIj4KCQk8Y2lyY2xlIGZpbGw9IiNGRkYiIHI9IjUwIiBjeD0iNTAiIGN5PSI1MCIvPgoJCTxnIGZpbGw9IiMwMDAiPgoJCTxjaXJjbGUgcj0iMjUiIGN4PSI1MCIgY3k9IjUwIiAvPgoJCTxjaXJjbGUgcj0iMTIiIGN4PSIwIiBjeT0iNTAiIC8+CgkJPGNpcmNsZSByPSIxMiIgY3g9IjUwIiBjeT0iMCIgLz4KCQk8Y2lyY2xlIHI9IjEyIiBjeD0iODUiIGN5PSIxNSIgLz4KCQk8Y2lyY2xlIHI9IjEyIiBjeD0iMTAwIiBjeT0iNTAiIC8+CgkJPGNpcmNsZSByPSIxMiIgY3g9Ijg1IiBjeT0iODUiIC8+CgkJPGNpcmNsZSByPSIxMiIgY3g9IjUwIiBjeT0iMTAwIiAvPgoJCTxjaXJjbGUgcj0iMTIiIGN4PSIxNSIgY3k9Ijg1IiAvPgoJCTxjaXJjbGUgcj0iMTIiIGN4PSIwIiBjeT0iNTAiIC8+CgkJPGNpcmNsZSByPSIxMiIgY3g9IjE1IiBjeT0iMTUiIC8+CgkJPC9nPgoJPC9tYXNrPgoJPGNpcmNsZSByPSI1MCIgY3g9IjUwIiBjeT0iNTAiIG1hc2s9InVybCgjY2xpcCkiIC8+Cjwvc3ZnPg=="
			}
		}
	],
	"clients":[
		{
			"clientId": "cryptomatorhub-system",
			"name": "Cryptomator Hub System",
			"clientAuthenticatorType": "client-secret",
			"standardFlowEnabled": false,
			"serviceAccountsEnabled": true,
			"publicClient": false,
			"enabled": true,
			"secret": "TODO"
		}
	]
}
EOF

In Keycloak

  1. Set secret in partial-realm-import.json to a secure value
  2. Partial import partial-realm-import.json realm
  3. Remove syncer user and syncer role

In the deployment

  1. Remove HUB_KEYCLOAK_SYNCER_USERNAME, HUB_KEYCLOAK_SYNCER_PASSWORD and HUB_KEYCLOAK_SYNCER_CLIENT_ID
  2. Add HUB_KEYCLOAK_SYSTEM_CLIENT_ID with value cryptomatorhub-system
  3. Add HUB_KEYCLOAK_SYSTEM_CLIENT_SECRET with the secret value of your partial-realm-import.json

@SailReal SailReal requested a review from overheadhunter March 26, 2025 15:06
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 26, 2025

Walkthrough

The changes introduce a new Java class, KeycloakProducer, in the org.cryptomator.hub package, which provides methods for producing and disposing of a Keycloak instance using builder patterns and configuration properties. Modifications have been made to the KeycloakRemoteUserProvider and VersionResource classes, which now receive an injected Keycloak instance directly, replacing the previous use of SyncerConfig and eliminating associated logic that filtered out a syncer user. Configuration updates in the application.properties file now utilize client credentials (client ID and client secret) for Keycloak integration instead of a username and password. The dev-realm.json file reflects the transition from the "syncer" role to a service account configuration and includes a new client configuration for the Cryptomator Hub System. Additionally, the tests in KeycloakRemoteUserProviderTest have been updated to remove the mocked syncer user.

Suggested reviewers

  • overheadunter

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 970bb9e and 1e6f7aa.

📒 Files selected for processing (6)
  • backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (1 hunks)
  • backend/src/main/java/org/cryptomator/hub/KeycloakRemoteUserProvider.java (5 hunks)
  • backend/src/main/java/org/cryptomator/hub/api/VersionResource.java (1 hunks)
  • backend/src/main/resources/application.properties (1 hunks)
  • backend/src/main/resources/dev-realm.json (2 hunks)
  • backend/src/test/java/org/cryptomator/hub/KeycloakRemoteUserProviderTest.java (3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (1)
backend/src/main/java/org/cryptomator/hub/KeycloakRemoteUserProvider.java (1)
  • ApplicationScoped (21-128)
🔇 Additional comments (15)
backend/src/test/java/org/cryptomator/hub/KeycloakRemoteUserProviderTest.java (3)

66-66: Tests updated to align with syncer client migration.

The test now correctly reflects the removal of the syncer user from the user list, aligning with the migration from a syncer user to a service account client pattern.


89-89: Tests consistently updated to remove syncer user.

Test case properly updated to maintain consistency with the first test case, ensuring the syncer user is no longer included in the test data.


152-152: Group membership tests correctly updated.

Group membership test data has been properly updated to reflect the removal of the syncer user, consistent with the architectural changes in the PR.

backend/src/main/java/org/cryptomator/hub/api/VersionResource.java (2)

21-21: Dependency updated to use direct Keycloak injection.

Clean replacement of the SyncerConfig dependency with a directly injected Keycloak instance, simplifying the class dependencies.


28-29: Simplified Keycloak version retrieval.

The code has been refactored to directly use the injected Keycloak instance, removing the need for try-with-resources and simplifying the method implementation.

backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (4)

1-12: Well-structured new producer class for Keycloak.

Clean implementation of a producer class using CDI for managing Keycloak instances. The class is properly scoped as ApplicationScoped, which is appropriate for this use case.


14-24: Properly configured injection of client credential properties.

Configuration properties are correctly set up to inject the client ID, client secret, URL, and realm from application properties, supporting the migration to client credentials authentication.


26-36: Effective implementation of Keycloak instance production.

The producer method correctly builds and configures a Keycloak instance using the KeycloakBuilder with proper client credentials configuration. The method is appropriately annotated with @produces and @ApplicationScoped.


38-40: Proper resource cleanup with @Disposes.

Excellent implementation of resource cleanup with the @Disposes method to ensure the Keycloak instance is properly closed when it's no longer needed, preventing resource leaks.

backend/src/main/resources/application.properties (2)

41-42: Client credentials properly configured for development environment.

Configuration has been properly updated to use the new client ID "cryptomatorhub-syncer" and client secret "top-secret" for the development environment.

Ensure the client secret "top-secret" is replaced with a secure value in production. This appears to be a development placeholder.


44-45: Test environment configuration consistent with development.

Test environment configuration correctly mirrors the development settings for client ID and secret, maintaining consistency across environments.

backend/src/main/resources/dev-realm.json (1)

127-127: Migration to service account is a good security improvement

Converting the syncer from a regular user to a service account with client credentials flow is a significant security improvement. This follows OAuth best practices for service-to-service authentication and aligns with the existing pattern used for the CLI client.

Also applies to: 232-241

backend/src/main/java/org/cryptomator/hub/KeycloakRemoteUserProvider.java (3)

28-31: Improve dependency management with direct Keycloak injection

The direct injection of Keycloak and use of ConfigProperty for the realm name improves the code structure by:

  1. Leveraging dependency injection rather than manual creation
  2. Making the code more testable
  3. Centralizing Keycloak instance management

This change aligns well with dependency injection best practices.


35-35: Code is now simpler and more maintainable

The simplified method calls using the injected Keycloak instance and realm name make the code more concise and easier to maintain.

Also applies to: 85-85


44-44:

Details

✅ Verification successful

Removal of user filtering is consistent with service account approach

The removal of code that filtered out the "syncer" user is appropriate now that it's a service account. This simplifies the code and represents the architectural change correctly.

However, verify that any code that processes these user lists doesn't have assumptions about syncers being filtered out.

Also applies to: 126-126


🏁 Script executed:

#!/bin/bash
# Check if there are other parts of the codebase that might expect syncers to be filtered
echo "Searching for references to syncer filtering in the codebase..."
rg -i "synceruser|syncerconfig|filtersync|syncerfilter" --type java

Length of output: 426


Syncer filtering removal verified – no downstream assumptions detected

The removal of the user filtering logic for the "syncer" account is consistent with the new service account approach. Our search only revealed references to SyncerConfig in a test (KeycloakRemoteUserProviderTest.java) and in SyncerConfig.java, with no additional filtering logic. There don’t appear to be any downstream assumptions about syncers being filtered out in the production code.

  • Production Code: The removal at lines 44 and 126 in KeycloakRemoteUserProvider.java aligns with the updated architectural strategy.
  • Test Code: Although the test file instantiates a SyncerConfig, it doesn’t enforce any syncer filtering behavior.
  • Overall Impact: No further modifications are required, but remain cautious if other parts modify or depend on the syncer configuration.

@overheadhunter
Copy link
Member

overheadhunter commented Mar 26, 2025

In-depth review will take a while, but what comes to mind immediately is the fact that the client will no longer "just sync" but be in charge of everything that hub needs to do in keycloak. Hence I would drop the name "syncer" for good.

@SailReal
Copy link
Member Author

SailReal commented Mar 26, 2025

You are right, I wanted to keep the diff as small as possible and also what the admin needs to do, but as we are doing a partial import we can also introduce a new composite role and ask the admin to remove the syncer role...will think of a better name.

@overheadhunter
Copy link
Member

How about just "hub"? After all this is the piece of software that is communicating with kc.

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: 0

🧹 Nitpick comments (4)
backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (2)

17-18: Consider securing the client secret

While the implementation is correct, consider adding additional safeguards for the client secret such as validating it's not empty at runtime.

@ConfigProperty(name = "hub.keycloak.client-secret")
String clientSecret;

+ public void validateConfig() {
+   if (clientSecret == null || clientSecret.trim().isEmpty()) {
+     throw new IllegalStateException("hub.keycloak.client-secret must be configured");
+   }
+ }

38-40: Add exception handling to disposeKeycloak method

The close() method might throw an exception. Consider adding try-catch to ensure proper resource cleanup.

public void disposeKeycloak(@Disposes Keycloak keycloak) {
-	keycloak.close();
+	try {
+		keycloak.close();
+	} catch (Exception e) {
+		// Log the exception but don't rethrow to ensure cleanup continues
+		System.err.println("Error closing Keycloak client: " + e.getMessage());
+	}
}
backend/src/main/resources/application.properties (2)

41-42: Use more descriptive client_id value

According to the PR objectives, the client ID should be "cryptomatorhub-syncer" to be more descriptive about its purpose. Consider updating the value to match the PR objectives.

-%dev.hub.keycloak.client-id=hub
+%dev.hub.keycloak.client-id=cryptomatorhub-syncer

42-42: Use placeholder for client secret in development config

While "top-secret" works for local development, consider using a placeholder that clearly indicates this should be replaced in production.

-%dev.hub.keycloak.client-secret=top-secret
+%dev.hub.keycloak.client-secret=change-me-in-production
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e6f7aa and 7d0f389.

📒 Files selected for processing (5)
  • backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (1 hunks)
  • backend/src/main/java/org/cryptomator/hub/SyncerConfig.java (0 hunks)
  • backend/src/main/resources/application.properties (1 hunks)
  • backend/src/main/resources/dev-realm.json (2 hunks)
  • backend/src/test/java/org/cryptomator/hub/KeycloakRemoteUserProviderTest.java (3 hunks)
💤 Files with no reviewable changes (1)
  • backend/src/main/java/org/cryptomator/hub/SyncerConfig.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/src/main/resources/dev-realm.json
  • backend/src/test/java/org/cryptomator/hub/KeycloakRemoteUserProviderTest.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Run Tests
🔇 Additional comments (2)
backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (1)

11-40: Well-designed Keycloak producer class

This class implements the client credentials flow for Keycloak authentication, which aligns with the PR objective of migrating from syncer user to client-based authentication. The implementation follows CDI best practices with proper @Produces and @Disposes annotations.

backend/src/main/resources/application.properties (1)

41-44:

Details

❓ Verification inconclusive

Client credentials configuration added correctly

The configuration properties have been updated to use client ID and client secret instead of username/password, which matches the PR objectives. The development values are suitable for testing purposes.

Run the following script to confirm that the removed syncer-username and syncer-password properties are no longer used:


🏁 Script executed:

#!/bin/bash
# Search for any remaining references to removed configuration properties
echo "Checking for any remaining references to syncer-username and syncer-password"
rg "syncer-username|syncer-password" --type java

Length of output: 213


Configuration Update Verified – Manual Verification Requested

The client credentials configuration now properly uses the client ID and client secret as intended by the PR. The shell script targeting Java files did not return any references to the removed syncer-username and syncer-password properties. However, because the search was limited to Java files and produced no output (beyond the header), please manually verify that these removed properties are not referenced elsewhere in the codebase (for example, in configuration files such as properties or YAML).

  • Confirm that a global search (without file-type restrictions) yields no instances of syncer-username or syncer-password.

For future changes where we use this client to create users/groups but
also partial import realm for changes like in this PR, this is required.
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

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d0f389 and 05f97af.

📒 Files selected for processing (3)
  • backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (1 hunks)
  • backend/src/main/resources/application.properties (1 hunks)
  • backend/src/main/resources/dev-realm.json (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/src/main/resources/dev-realm.json
🧰 Additional context used
🧬 Code Definitions (1)
backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (1)
backend/src/main/java/org/cryptomator/hub/KeycloakRemoteUserProvider.java (1)
  • ApplicationScoped (21-128)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Run Tests
🔇 Additional comments (4)
backend/src/main/java/org/cryptomator/hub/KeycloakProducer.java (4)

1-12: New class design follows CDI best practices

This newly added KeycloakProducer class is well-structured with the appropriate @ApplicationScoped annotation, making it a singleton within the application context. This follows CDI best practices for centralized resource management.


14-24: Configuration properties correctly defined

The configuration properties are properly defined with descriptive names, and they align with the changes in the application.properties file. The naming convention clearly indicates their purpose, with "system-client-id" and "system-client-secret" replacing the previous syncer username/password approach.


26-36: Secure Keycloak instance creation with client credentials

The produceKeycloak() method correctly uses the builder pattern to create a Keycloak instance. The switch to CLIENT_CREDENTIALS grant type is a more secure approach than the previous username/password authentication, as it follows OAuth 2.0 best practices for service-to-service authentication.


38-40: Proper resource cleanup

The disposeKeycloak() method correctly uses the @Disposes annotation to ensure the Keycloak instance is properly closed when it's no longer needed, preventing resource leaks.

@SailReal SailReal changed the title Migrate syncer user to syncer client Migrate syncer user to cryptomatorhub-system client Mar 26, 2025
@SailReal SailReal added this to the 1.4.0 milestone Mar 26, 2025
Copy link
Member

@overheadhunter overheadhunter left a comment

Choose a reason for hiding this comment

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

now that KC supports longer attributes (at least for users - not for groups), we may include base64-encoded images.

@SailReal SailReal requested a review from overheadhunter March 27, 2025 09:59
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: 0

♻️ Duplicate comments (1)
backend/src/main/resources/dev-realm.json (1)

225-234: ⚠️ Potential issue

Update the Client Secret for "cryptomatorhub-system"

The new client configuration uses a hardcoded secret value "top-secret", which is insecure even for development environments and may unintentionally serve as a template for production. It is recommended to replace this with a secure, environment-specific placeholder (for example, "${GENERATED_SECRET}") or to ensure that a secure secret is injected via configuration.

Proposed diff:

-      "secret": "top-secret",
+      "secret": "${GENERATED_SECRET}",
🧹 Nitpick comments (1)
backend/src/main/resources/dev-realm.json (1)

111-121: Review the Service Account User "system" Setup and Privileges

The new "system" user configuration is set up to operate as a service account using the "serviceAccountClientId" field, which is correctly linked to the new client. The inline base64-encoded SVG for the picture attribute is a good way to avoid external dependencies and potential XSS risks. Please verify that omitting fields like "firstName" and "lastName" is intentional for a service account. Additionally, ensure that granting the "realm-admin" role via "clientRoles" aligns with your intended security model since it confers broad privileges.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05f97af and 94b4955.

📒 Files selected for processing (1)
  • backend/src/main/resources/dev-realm.json (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Run Tests

@SailReal SailReal merged commit 508b532 into develop Mar 27, 2025
8 checks passed
@SailReal SailReal deleted the feature/migrate-syncer-to-client branch March 27, 2025 11:41
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