This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 06418390cd1 CAMEL-22459 - Camel-Keycloak: Support permission based
policies (#19358)
06418390cd1 is described below
commit 06418390cd1b007c66683a47a4d4b9c517d52745
Author: Andrea Cosentino <[email protected]>
AuthorDate: Mon Sep 29 12:21:40 2025 +0200
CAMEL-22459 - Camel-Keycloak: Support permission based policies (#19358)
Signed-off-by: Andrea Cosentino <[email protected]>
---
.../camel-keycloak/src/main/docs/keycloak.adoc | 181 +++++++++++++++++++++
.../keycloak/security/KeycloakSecurityHelper.java | 24 +++
.../security/KeycloakSecurityProcessor.java | 35 ++++
.../security/KeycloakSecurityHelperTest.java | 71 ++++++++
.../keycloak/security/KeycloakSecurityIT.java | 165 +++++++++++++++++++
5 files changed, 476 insertions(+)
diff --git a/components/camel-keycloak/src/main/docs/keycloak.adoc
b/components/camel-keycloak/src/main/docs/keycloak.adoc
index ce70d21939d..d0342c3a1f5 100644
--- a/components/camel-keycloak/src/main/docs/keycloak.adoc
+++ b/components/camel-keycloak/src/main/docs/keycloak.adoc
@@ -819,6 +819,16 @@ beans:
The component includes integration tests that require a running Keycloak
instance. These tests are disabled by default and only run when specific system
properties are provided.
+The integration tests include comprehensive testing for:
+* Role-based authorization with different role requirements
+* Permission-based authorization using custom claims and scopes
+* Public key verification with JWKS endpoint integration
+* Combined roles and permissions validation
+* Token parsing with and without public key verification
+* Different authorization header formats (Bearer token, custom header)
+* Token expiration and validity checks
+* Error handling for invalid tokens and insufficient privileges
+
=== Starting Keycloak with Docker
==== 1. Start Keycloak Container
@@ -898,6 +908,7 @@ Create three test users with the following configuration:
==== 7. Execute Tests with Maven
+**Run All Integration Tests:**
[source,bash]
----
# Run integration tests with required properties
@@ -908,6 +919,31 @@ mvn test -Dtest=KeycloakSecurityIT \
-Dkeycloak.client.secret=YOUR_CLIENT_SECRET
----
+**Run Specific Test Categories:**
+[source,bash]
+----
+# Test only role-based authorization
+mvn test
-Dtest=KeycloakSecurityIT#testKeycloakSecurityPolicyWithValidAdminToken,testKeycloakSecurityPolicyWithValidUserToken,testKeycloakSecurityPolicyUserCannotAccessAdminRoute
\
+ -Dkeycloak.server.url=http://localhost:8080 \
+ -Dkeycloak.realm=test-realm \
+ -Dkeycloak.client.id=test-client \
+ -Dkeycloak.client.secret=YOUR_CLIENT_SECRET
+
+# Test only permissions-based authorization
+mvn test
-Dtest=KeycloakSecurityIT#testKeycloakSecurityPolicyWithPermissions,testKeycloakSecurityPolicyWithScopeBasedPermissions,testKeycloakSecurityPolicyWithCombinedRolesAndPermissions
\
+ -Dkeycloak.server.url=http://localhost:8080 \
+ -Dkeycloak.realm=test-realm \
+ -Dkeycloak.client.id=test-client \
+ -Dkeycloak.client.secret=YOUR_CLIENT_SECRET
+
+# Test only public key verification
+mvn test
-Dtest=KeycloakSecurityIT#testKeycloakSecurityPolicyWithPublicKeyVerification,testParseTokenDirectlyWithPublicKey
\
+ -Dkeycloak.server.url=http://localhost:8080 \
+ -Dkeycloak.realm=test-realm \
+ -Dkeycloak.client.id=test-client \
+ -Dkeycloak.client.secret=YOUR_CLIENT_SECRET
+----
+
Replace `YOUR_CLIENT_SECRET` with the actual client secret from step 4.
==== 8. Alternative: Set Environment Variables
@@ -939,3 +975,148 @@ mvn test -Dtest=KeycloakSecurityIT \
**Connection refused**: Ensure Keycloak is running and accessible at the
specified URL.
**Token validation errors**: Verify the realm name and client configuration
match exactly.
+
+=== Setting up Permissions in Keycloak
+
+For permissions-based authorization, you have several options to include
permissions in tokens:
+
+==== Option 1: Custom Claims Mapper
+
+1. In your realm, go to **Client Scopes** → **roles** → **Mappers** → **Create
mapper**
+2. Set the following:
+ - Mapper Type: `User Attribute`
+ - Name: `permissions-mapper`
+ - User Attribute: `permissions`
+ - Token Claim Name: `permissions`
+ - Claim JSON Type: `JSON`
+ - Add to ID token: `ON`
+ - Add to access token: `ON`
+
+3. Add the `permissions` attribute to users:
+ - Go to **Users** → Select user → **Attributes** tab
+ - Add attribute: `permissions` with value like `["read:documents",
"write:documents"]`
+
+==== Option 2: Scope-based Permissions
+
+1. Configure client scopes:
+ - Go to **Client Scopes** → **Create client scope**
+ - Scope Name: `documents`
+ - Protocol: `openid-connect`
+
+2. Add scope to client:
+ - Go to **Clients** → Your client → **Client Scopes** tab
+ - Add the scope as **Default** or **Optional**
+
+3. In your application code, you can then use scopes as permissions:
+
+[source,java]
+----
+KeycloakSecurityPolicy policy = new KeycloakSecurityPolicy();
+policy.setRequiredPermissions(Arrays.asList("documents", "users", "admin"));
+policy.setAllPermissionsRequired(false); // ANY permission
+----
+
+==== Option 3: Authorization Services (Advanced)
+
+For complex permission models, enable Keycloak Authorization Services:
+
+1. Go to **Clients** → Your client → **Settings** → **Authorization Enabled**:
`ON`
+2. Configure Resources, Scopes, and Policies in the **Authorization** tab
+3. Enable **Authorization** on the client
+
+Note: Full Authorization Services integration requires additional setup and is
more complex than the simple approaches above.
+
+=== Combined Roles and Permissions Example
+
+[tabs]
+====
+Java::
++
+[source,java]
+----
+// Create a policy that requires BOTH roles AND permissions
+KeycloakSecurityPolicy strictPolicy = new KeycloakSecurityPolicy();
+strictPolicy.setServerUrl("{{keycloak.server-url}}");
+strictPolicy.setRealm("{{keycloak.realm}}");
+strictPolicy.setClientId("{{keycloak.client-id}}");
+strictPolicy.setClientSecret("{{keycloak.client-secret}}");
+
+// User must have admin role AND document permissions
+strictPolicy.setRequiredRoles(Arrays.asList("admin"));
+strictPolicy.setRequiredPermissions(Arrays.asList("read:documents",
"write:documents"));
+strictPolicy.setAllRolesRequired(true);
+strictPolicy.setAllPermissionsRequired(false); // ANY permission
+
+// Create a policy that requires EITHER roles OR permissions
+KeycloakSecurityPolicy flexiblePolicy = new KeycloakSecurityPolicy();
+flexiblePolicy.setServerUrl("{{keycloak.server-url}}");
+flexiblePolicy.setRealm("{{keycloak.realm}}");
+flexiblePolicy.setClientId("{{keycloak.client-id}}");
+flexiblePolicy.setClientSecret("{{keycloak.client-secret}}");
+
+// Apply different policies to different routes
+from("direct:admin-documents")
+ .policy(strictPolicy)
+ .to("bean:documentService?method=adminOperations");
+
+from("direct:flexible-access")
+ .policy(flexiblePolicy)
+ .to("bean:documentService?method=flexibleOperations");
+----
+
+YAML::
++
+[source,yaml]
+----
+- route:
+ from:
+ uri: direct:admin-documents
+ steps:
+ - policy:
+ ref: strictPolicy
+ - to:
+ uri: bean:documentService?method=adminOperations
+
+- route:
+ from:
+ uri: direct:flexible-access
+ steps:
+ - policy:
+ ref: flexiblePolicy
+ - to:
+ uri: bean:documentService?method=flexibleOperations
+
+# Bean definitions
+beans:
+ - name: strictPolicy
+ type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
+ properties:
+ serverUrl: "{{keycloak.server-url}}"
+ realm: "{{keycloak.realm}}"
+ clientId: "{{keycloak.client-id}}"
+ clientSecret: "{{keycloak.client-secret}}"
+ requiredRoles:
+ - "admin"
+ requiredPermissions:
+ - "read:documents"
+ - "write:documents"
+ allRolesRequired: true
+ allPermissionsRequired: false
+
+ - name: flexiblePolicy
+ type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
+ properties:
+ serverUrl: "{{keycloak.server-url}}"
+ realm: "{{keycloak.realm}}"
+ clientId: "{{keycloak.client-id}}"
+ clientSecret: "{{keycloak.client-secret}}"
+ requiredRoles:
+ - "admin"
+ - "manager"
+ requiredPermissions:
+ - "read:documents"
+ - "emergency:access"
+ allRolesRequired: false
+ allPermissionsRequired: false
+----
+====
diff --git
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelper.java
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelper.java
index c845ada2eca..dfa8c081c90 100644
---
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelper.java
+++
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelper.java
@@ -17,6 +17,7 @@
package org.apache.camel.component.keycloak.security;
import java.security.PublicKey;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -121,4 +122,27 @@ public final class KeycloakSecurityHelper {
return true;
}
+
+ public static Set<String> extractPermissions(AccessToken token) {
+ Set<String> permissions = new HashSet<>();
+
+ // Extract permissions from custom claims (primary approach for simple
setups)
+ Object permissionsClaim = token.getOtherClaims().get("permissions");
+ if (permissionsClaim instanceof java.util.Collection<?>) {
+ @SuppressWarnings("unchecked")
+ java.util.Collection<String> permissionsCollection =
(java.util.Collection<String>) permissionsClaim;
+ permissions.addAll(permissionsCollection);
+ }
+
+ // Also check for scope-based permissions
+ Object scopesClaim = token.getOtherClaims().get("scope");
+ if (scopesClaim instanceof String) {
+ String scopesString = (String) scopesClaim;
+ if (!scopesString.isEmpty()) {
+
permissions.addAll(java.util.Arrays.asList(scopesString.split(" ")));
+ }
+ }
+
+ return permissions;
+ }
}
diff --git
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityProcessor.java
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityProcessor.java
index 2338c3b66df..a47868f00f7 100644
---
a/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityProcessor.java
+++
b/components/camel-keycloak/src/main/java/org/apache/camel/component/keycloak/security/KeycloakSecurityProcessor.java
@@ -55,6 +55,10 @@ public class KeycloakSecurityProcessor extends
DelegateProcessor {
validateRoles(accessToken, exchange);
}
+ if (!policy.getRequiredPermissions().isEmpty()) {
+ validatePermissions(accessToken, exchange);
+ }
+
} catch (Exception e) {
exchange.getIn().setHeader(Exchange.AUTHENTICATION_FAILURE_POLICY_ID,
policy.getClass().getSimpleName());
@@ -116,4 +120,35 @@ public class KeycloakSecurityProcessor extends
DelegateProcessor {
}
}
+ private void validatePermissions(String accessToken, Exchange exchange)
throws Exception {
+ try {
+ AccessToken token;
+ if (ObjectHelper.isEmpty(policy.getPublicKey())) {
+ token = KeycloakSecurityHelper.parseAccessToken(accessToken);
+ } else {
+ token = KeycloakSecurityHelper.parseAccessToken(accessToken,
policy.getPublicKey());
+ }
+ Set<String> userPermissions =
KeycloakSecurityHelper.extractPermissions(token);
+
+ boolean hasRequiredPermissions = policy.isAllPermissionsRequired()
+ ?
userPermissions.containsAll(policy.getRequiredPermissions())
+ :
policy.getRequiredPermissions().stream().anyMatch(userPermissions::contains);
+
+ if (!hasRequiredPermissions) {
+ String message = String.format("User does not have required
permissions. Required: %s, User has: %s",
+ policy.getRequiredPermissions(), userPermissions);
+ LOG.debug(message);
+ throw new CamelAuthorizationException(message, exchange);
+ }
+
+ LOG.debug("Permission validation successful for user with
permissions: {}", userPermissions);
+
+ } catch (Exception e) {
+ if (e instanceof CamelAuthorizationException) {
+ throw e;
+ }
+ throw new CamelAuthorizationException("Failed to validate
permissions", exchange, e);
+ }
+ }
+
}
diff --git
a/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelperTest.java
b/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelperTest.java
index 718123c9dce..50372227fdc 100644
---
a/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelperTest.java
+++
b/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityHelperTest.java
@@ -160,4 +160,75 @@ public class KeycloakSecurityHelperTest {
});
}
+ @Test
+ void testExtractPermissions() {
+ AccessToken token = Mockito.mock(AccessToken.class);
+
+ // Mock authorization (simple approach without specific permission
structure)
+ AccessToken.Authorization authorization =
Mockito.mock(AccessToken.Authorization.class);
+ when(token.getAuthorization()).thenReturn(authorization);
+
+ // Test permissions extraction from custom claims
+ java.util.Map<String, Object> otherClaims = new java.util.HashMap<>();
+ otherClaims.put("permissions",
java.util.Arrays.asList("read:documents", "write:documents", "admin:users"));
+
+ when(token.getOtherClaims()).thenReturn(otherClaims);
+
+ java.util.Set<String> permissions =
KeycloakSecurityHelper.extractPermissions(token);
+
+ assertEquals(3, permissions.size());
+ assertTrue(permissions.contains("read:documents"));
+ assertTrue(permissions.contains("write:documents"));
+ assertTrue(permissions.contains("admin:users"));
+ }
+
+ @Test
+ void testExtractPermissionsFromCustomClaims() {
+ AccessToken token = Mockito.mock(AccessToken.class);
+
+ // Mock other claims with permissions
+ java.util.Map<String, Object> otherClaims = new java.util.HashMap<>();
+ otherClaims.put("permissions", java.util.Arrays.asList("read:files",
"write:files", "delete:files"));
+
+ when(token.getOtherClaims()).thenReturn(otherClaims);
+ when(token.getAuthorization()).thenReturn(null);
+
+ java.util.Set<String> permissions =
KeycloakSecurityHelper.extractPermissions(token);
+
+ assertEquals(3, permissions.size());
+ assertTrue(permissions.contains("read:files"));
+ assertTrue(permissions.contains("write:files"));
+ assertTrue(permissions.contains("delete:files"));
+ }
+
+ @Test
+ void testExtractPermissionsFromScopes() {
+ AccessToken token = Mockito.mock(AccessToken.class);
+
+ // Mock other claims with scope-based permissions
+ java.util.Map<String, Object> otherClaims = new java.util.HashMap<>();
+ otherClaims.put("scope", "read write admin");
+
+ when(token.getOtherClaims()).thenReturn(otherClaims);
+ when(token.getAuthorization()).thenReturn(null);
+
+ java.util.Set<String> permissions =
KeycloakSecurityHelper.extractPermissions(token);
+
+ assertEquals(3, permissions.size());
+ assertTrue(permissions.contains("read"));
+ assertTrue(permissions.contains("write"));
+ assertTrue(permissions.contains("admin"));
+ }
+
+ @Test
+ void testExtractPermissionsEmpty() {
+ AccessToken token = Mockito.mock(AccessToken.class);
+ when(token.getAuthorization()).thenReturn(null);
+ when(token.getOtherClaims()).thenReturn(java.util.Map.of());
+
+ java.util.Set<String> permissions =
KeycloakSecurityHelper.extractPermissions(token);
+
+ assertTrue(permissions.isEmpty());
+ }
+
}
diff --git
a/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityIT.java
b/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityIT.java
index 05169c82b4a..ea315ba2e0d 100644
---
a/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityIT.java
+++
b/components/camel-keycloak/src/test/java/org/apache/camel/component/keycloak/security/KeycloakSecurityIT.java
@@ -260,6 +260,111 @@ public class KeycloakSecurityIT extends CamelTestSupport {
assertTrue(ex.getMessage().contains("signature") ||
ex.getMessage().contains("verification"));
}
+ @Test
+ void testKeycloakSecurityPolicyWithPermissions() {
+ // Test permissions-based authorization
+ String adminToken = getAccessToken("myuser", "pippo123");
+ assertNotNull(adminToken);
+
+ // Test with permissions policy route - this will test the permissions
extraction
+ try {
+ String result =
template.requestBodyAndHeader("direct:permissions-protected", "test message",
+ KeycloakSecurityConstants.ACCESS_TOKEN_HEADER, adminToken,
String.class);
+ assertEquals("Permissions access granted", result);
+ } catch (CamelExecutionException ex) {
+ // This might fail if permissions are not configured in the token
+ // which is expected in a basic Keycloak setup
+ assertTrue(ex.getCause() instanceof CamelAuthorizationException);
+ }
+ }
+
+ @Test
+ void testKeycloakSecurityPolicyWithInsufficientPermissions() {
+ // Test that users without required permissions are rejected
+ String userToken = getAccessToken("test-user", "user123");
+ assertNotNull(userToken);
+
+ CamelExecutionException ex =
assertThrows(CamelExecutionException.class, () -> {
+ template.sendBodyAndHeader("direct:permissions-protected", "test
message",
+ KeycloakSecurityConstants.ACCESS_TOKEN_HEADER, userToken);
+ });
+ assertTrue(ex.getCause() instanceof CamelAuthorizationException);
+ }
+
+ @Test
+ void testKeycloakSecurityPolicyWithScopeBasedPermissions() {
+ // Test scope-based permissions (using standard OAuth2 scopes)
+ String adminToken = getAccessToken("myuser", "pippo123");
+ assertNotNull(adminToken);
+
+ // Test with scope-based permissions policy route
+ try {
+ String result =
template.requestBodyAndHeader("direct:scope-permissions-protected", "test
message",
+ KeycloakSecurityConstants.ACCESS_TOKEN_HEADER, adminToken,
String.class);
+ assertEquals("Scope permissions access granted", result);
+ } catch (CamelExecutionException ex) {
+ // This might fail if the token doesn't contain the expected scopes
+ // which is expected in basic Keycloak setup without custom scope
configuration
+ assertTrue(ex.getCause() instanceof CamelAuthorizationException);
+ }
+ }
+
+ @Test
+ void testKeycloakSecurityPolicyWithCombinedRolesAndPermissions() {
+ // Test combined roles and permissions validation
+ String adminToken = getAccessToken("myuser", "pippo123");
+ assertNotNull(adminToken);
+
+ // Test with combined policy route (requires BOTH admin role AND
permissions)
+ try {
+ String result =
template.requestBodyAndHeader("direct:combined-protected", "test message",
+ KeycloakSecurityConstants.ACCESS_TOKEN_HEADER, adminToken,
String.class);
+ assertEquals("Combined access granted", result);
+ } catch (CamelExecutionException ex) {
+ // This will fail if either role or permissions are missing
+ assertTrue(ex.getCause() instanceof CamelAuthorizationException);
+ }
+ }
+
+ @Test
+ void testKeycloakSecurityPolicyWithFlexiblePermissions() {
+ // Test flexible permissions (ANY permission required)
+ String userToken = getAccessToken("test-user", "user123");
+ assertNotNull(userToken);
+
+ // Test with flexible permissions policy (requires ANY of the
specified permissions)
+ try {
+ String result =
template.requestBodyAndHeader("direct:flexible-permissions-protected", "test
message",
+ KeycloakSecurityConstants.ACCESS_TOKEN_HEADER, userToken,
String.class);
+ assertEquals("Flexible permissions access granted", result);
+ } catch (CamelExecutionException ex) {
+ // This will fail if the user doesn't have any of the required
permissions
+ assertTrue(ex.getCause() instanceof CamelAuthorizationException);
+ }
+ }
+
+ @Test
+ void testPermissionsExtractionFromToken() {
+ // Test direct permissions extraction from token for debugging
+ String adminToken = getAccessToken("myuser", "pippo123");
+ assertNotNull(adminToken);
+
+ try {
+ // Parse token and extract permissions directly
+ org.keycloak.representations.AccessToken token =
KeycloakSecurityHelper.parseAccessToken(adminToken);
+ java.util.Set<String> permissions =
KeycloakSecurityHelper.extractPermissions(token);
+
+ // Log the permissions found for debugging
+ System.out.println("Permissions found in token: " + permissions);
+
+ // Permissions might be empty in a basic setup, which is expected
+ assertNotNull(permissions);
+
+ } catch (Exception e) {
+ fail("Should be able to parse token and extract permissions: " +
e.getMessage());
+ }
+ }
+
/**
* Helper method to get public key from Keycloak JWKS endpoint for token
verification. Tries to find the key with
* "sig" usage or the first RSA key available.
@@ -451,6 +556,66 @@ public class KeycloakSecurityIT extends CamelTestSupport {
.policy(wrongPublicKeyPolicy)
.transform().constant("Should not reach here")
.to("mock:wrong-key-result");
+
+ // Permissions-based policy
+ KeycloakSecurityPolicy permissionsPolicy = new
KeycloakSecurityPolicy();
+ permissionsPolicy.setServerUrl(keycloakUrl);
+ permissionsPolicy.setRealm(realm);
+ permissionsPolicy.setClientId(clientId);
+ permissionsPolicy.setClientSecret(clientSecret);
+
permissionsPolicy.setRequiredPermissions(java.util.Arrays.asList("read:documents",
"write:documents"));
+ permissionsPolicy.setAllPermissionsRequired(false); // ANY
permission
+
+ from("direct:permissions-protected")
+ .policy(permissionsPolicy)
+ .transform().constant("Permissions access granted")
+ .to("mock:permissions-result");
+
+ // Scope-based permissions policy (using OAuth2 scopes)
+ KeycloakSecurityPolicy scopePermissionsPolicy = new
KeycloakSecurityPolicy();
+ scopePermissionsPolicy.setServerUrl(keycloakUrl);
+ scopePermissionsPolicy.setRealm(realm);
+ scopePermissionsPolicy.setClientId(clientId);
+ scopePermissionsPolicy.setClientSecret(clientSecret);
+
scopePermissionsPolicy.setRequiredPermissions(java.util.Arrays.asList("profile",
"email", "openid"));
+ scopePermissionsPolicy.setAllPermissionsRequired(false); //
ANY scope
+
+ from("direct:scope-permissions-protected")
+ .policy(scopePermissionsPolicy)
+ .transform().constant("Scope permissions access
granted")
+ .to("mock:scope-permissions-result");
+
+ // Combined roles and permissions policy
+ KeycloakSecurityPolicy combinedPolicy = new
KeycloakSecurityPolicy();
+ combinedPolicy.setServerUrl(keycloakUrl);
+ combinedPolicy.setRealm(realm);
+ combinedPolicy.setClientId(clientId);
+ combinedPolicy.setClientSecret(clientSecret);
+
combinedPolicy.setRequiredRoles(java.util.Arrays.asList("admin-role"));
+
combinedPolicy.setRequiredPermissions(java.util.Arrays.asList("read:documents",
"admin:system"));
+ combinedPolicy.setAllRolesRequired(true); // Must have ALL
roles
+ combinedPolicy.setAllPermissionsRequired(true); // Any
permission
+
+ from("direct:combined-protected")
+ .policy(combinedPolicy)
+ .transform().constant("Combined access granted")
+ .to("mock:combined-result");
+
+ // Flexible permissions policy (ANY permission)
+ KeycloakSecurityPolicy flexiblePermissionsPolicy = new
KeycloakSecurityPolicy();
+ flexiblePermissionsPolicy.setServerUrl(keycloakUrl);
+ flexiblePermissionsPolicy.setRealm(realm);
+ flexiblePermissionsPolicy.setClientId(clientId);
+ flexiblePermissionsPolicy.setClientSecret(clientSecret);
+ flexiblePermissionsPolicy
+
.setRequiredPermissions(java.util.Arrays.asList("profile", "email",
"user:basic", "read:public"));
+ flexiblePermissionsPolicy.setAllPermissionsRequired(false); //
ANY permission
+
+ from("direct:flexible-permissions-protected")
+ .policy(flexiblePermissionsPolicy)
+ .transform().constant("Flexible permissions access
granted")
+ .to("mock:flexible-permissions-result");
+
}
};
}