blob: bd1dd9f7b216de9b81ec450ca08312d2b99cb715 [file] [log] [blame]
= Keycloak Component
:doctitle: Keycloak
:shortname: keycloak
:artifactid: camel-keycloak
:description: Manage Keycloak instances via Admin API.
:since: 4.15
:supportlevel: Preview
:tabs-sync-option:
:component-header: Only producer is supported
//Manually maintained attributes
:camel-spring-boot-name: keycloak
*Since Camel {since}*
*{component-header}*
The Keycloak component supports running operations on Keycloak instance and policy enforcements.
== Component Features
The Keycloak component provides two main functionalities:
1. **Producer Operations** - Manage Keycloak instances via the Admin API (realms, users, roles, clients)
2. **Security Policies** - Route-level authorization using Keycloak authentication and authorization services
== URI Format
-------------------------
keycloak://label[?options]
-------------------------
You can append query options to the URI in the following format:
`?options=value&option2=value&...`
// component-configure options: START
// component-configure options: END
// component options: START
include::partial$component-configure-options.adoc[]
include::partial$component-endpoint-options.adoc[]
// component options: END
// endpoint options: START
// endpoint options: END
== Producer Operations
The Keycloak producer supports administrative operations on Keycloak instances via the Admin API.
=== Configuration
To use the producer, configure the Keycloak connection details:
[tabs]
====
Java::
+
[source,java]
----
// Configure Keycloak component
KeycloakComponent keycloak = context.getComponent("keycloak", KeycloakComponent.class);
KeycloakConfiguration config = new KeycloakConfiguration();
config.setServerUrl("http://localhost:8080");
config.setRealm("master");
config.setUsername("admin");
config.setPassword("admin");
keycloak.setConfiguration(config);
----
YAML::
+
[source,yaml]
----
# Configuration in application.yaml
camel:
component:
keycloak:
server-url: "http://localhost:8080"
realm: "master"
username: "admin"
password: "admin"
----
====
=== Supported Operations
The component supports the following operations:
* **Realm Management**: `createRealm`, `getRealm`, `updateRealm`, `deleteRealm`
* **User Management**: `createUser`, `getUser`, `updateUser`, `listUsers`, `searchUsers`, `deleteUser`
* **Role Management**: `createRole`, `getRole`, `updateRole`, `listRoles`, `deleteRole`, `assignRoleToUser`, `removeRoleFromUser`, `getUserRoles`
* **Group Management**: `createGroup`, `getGroup`, `updateGroup`, `listGroups`, `deleteGroup`, `addUserToGroup`, `removeUserFromGroup`, `listUserGroups`
* **Client Management**: `createClient`, `getClient`, `updateClient`, `listClients`, `deleteClient`
* **Client Role Management**: `createClientRole`, `getClientRole`, `updateClientRole`, `listClientRoles`, `deleteClientRole`, `assignClientRoleToUser`, `removeClientRoleFromUser`
* **Password Management**: `resetUserPassword`
* **Session Management**: `listUserSessions`, `logoutUser`
* **Client Scope Management**: `createClientScope`, `getClientScope`, `updateClientScope`, `listClientScopes`, `deleteClientScope`
=== Realm Operations
[tabs]
====
Java::
+
[source,java]
----
// Create a new realm
template.sendBodyAndHeader("keycloak:admin?operation=createRealm", null,
KeycloakConstants.REALM_NAME, "my-new-realm");
// Get realm information
template.sendBodyAndHeader("keycloak:admin?operation=getRealm", null,
KeycloakConstants.REALM_NAME, "my-realm");
// Delete a realm
template.sendBodyAndHeader("keycloak:admin?operation=deleteRealm", null,
KeycloakConstants.REALM_NAME, "my-old-realm");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:create-realm
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-new-realm"
- to:
uri: keycloak:admin?operation=createRealm
- log: "Created realm: ${header.CamelKeycloakRealmName}"
- route:
from:
uri: direct:get-realm
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- to:
uri: keycloak:admin?operation=getRealm
- log: "Realm info: ${body}"
- route:
from:
uri: direct:delete-realm
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-old-realm"
- to:
uri: keycloak:admin?operation=deleteRealm
- log: "Deleted realm: ${header.CamelKeycloakRealmName}"
----
====
=== User Operations
[tabs]
====
Java::
+
[source,java]
----
// Create a new user
Map<String, Object> headers = new HashMap<>();
headers.put(KeycloakConstants.REALM_NAME, "my-realm");
headers.put(KeycloakConstants.USERNAME, "john.doe");
headers.put(KeycloakConstants.USER_EMAIL, "john.doe@example.com");
headers.put(KeycloakConstants.USER_FIRST_NAME, "John");
headers.put(KeycloakConstants.USER_LAST_NAME, "Doe");
template.sendBodyAndHeaders("keycloak:admin?operation=createUser", null, headers);
// Set user password
Map<String, Object> passwordHeaders = new HashMap<>();
passwordHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
passwordHeaders.put(KeycloakConstants.USERNAME, "john.doe");
passwordHeaders.put("CamelKeycloakUserPassword", "secure-password");
passwordHeaders.put("CamelKeycloakUserPasswordTemporary", false);
template.sendBodyAndHeaders("keycloak:admin?operation=setUserPassword", null, passwordHeaders);
// List all users in realm
template.sendBodyAndHeader("keycloak:admin?operation=listUsers", null,
KeycloakConstants.REALM_NAME, "my-realm");
// Delete a user
Map<String, Object> deleteHeaders = new HashMap<>();
deleteHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
deleteHeaders.put(KeycloakConstants.USERNAME, "john.doe");
template.sendBodyAndHeaders("keycloak:admin?operation=deleteUser", null, deleteHeaders);
----
YAML::
+
[source,yaml]
----
# Create user route
- route:
from:
uri: direct:create-user
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUsername
simple: "${body[username]}"
- setHeader:
name: CamelKeycloakUserEmail
simple: "${body[email]}"
- setHeader:
name: CamelKeycloakUserFirstName
simple: "${body[firstName]}"
- setHeader:
name: CamelKeycloakUserLastName
simple: "${body[lastName]}"
- to:
uri: keycloak:admin?operation=createUser
- log: "Created user: ${header.CamelKeycloakUsername}"
# Set user password route
- route:
from:
uri: direct:set-user-password
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUsername
simple: "${body[username]}"
- setHeader:
name: CamelKeycloakUserPassword
simple: "${body[password]}"
- setHeader:
name: CamelKeycloakUserPasswordTemporary
constant: false
- to:
uri: keycloak:admin?operation=setUserPassword
- log: "Set password for user: ${header.CamelKeycloakUsername}"
# List users route
- route:
from:
uri: direct:list-users
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- to:
uri: keycloak:admin?operation=listUsers
- log: "Users in realm: ${body}"
# Delete user route
- route:
from:
uri: direct:delete-user
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUsername
simple: "${body[username]}"
- to:
uri: keycloak:admin?operation=deleteUser
- log: "Deleted user: ${header.CamelKeycloakUsername}"
----
====
=== Role Operations
[tabs]
====
Java::
+
[source,java]
----
// Create a new role
Map<String, Object> roleHeaders = new HashMap<>();
roleHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
roleHeaders.put(KeycloakConstants.ROLE_NAME, "manager");
roleHeaders.put(KeycloakConstants.ROLE_DESCRIPTION, "Manager role with elevated privileges");
template.sendBodyAndHeaders("keycloak:admin?operation=createRole", null, roleHeaders);
// Get role information
Map<String, Object> getRoleHeaders = new HashMap<>();
getRoleHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
getRoleHeaders.put(KeycloakConstants.ROLE_NAME, "manager");
template.sendBodyAndHeaders("keycloak:admin?operation=getRole", null, getRoleHeaders);
// Assign role to user
Map<String, Object> assignHeaders = new HashMap<>();
assignHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
assignHeaders.put(KeycloakConstants.USERNAME, "john.doe");
assignHeaders.put(KeycloakConstants.ROLE_NAME, "manager");
template.sendBodyAndHeaders("keycloak:admin?operation=assignRoleToUser", null, assignHeaders);
// Delete a role
Map<String, Object> deleteRoleHeaders = new HashMap<>();
deleteRoleHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
deleteRoleHeaders.put(KeycloakConstants.ROLE_NAME, "old-role");
template.sendBodyAndHeaders("keycloak:admin?operation=deleteRole", null, deleteRoleHeaders);
----
YAML::
+
[source,yaml]
----
# Create role route
- route:
from:
uri: direct:create-role
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakRoleName
simple: "${body[roleName]}"
- setHeader:
name: CamelKeycloakRoleDescription
simple: "${body[description]}"
- to:
uri: keycloak:admin?operation=createRole
- log: "Created role: ${header.CamelKeycloakRoleName}"
# Get role route
- route:
from:
uri: direct:get-role
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakRoleName
simple: "${body[roleName]}"
- to:
uri: keycloak:admin?operation=getRole
- log: "Role info: ${body}"
# Assign role to user route
- route:
from:
uri: direct:assign-role
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUsername
simple: "${body[username]}"
- setHeader:
name: CamelKeycloakRoleName
simple: "${body[roleName]}"
- to:
uri: keycloak:admin?operation=assignRoleToUser
- log: "Assigned role ${header.CamelKeycloakRoleName} to user ${header.CamelKeycloakUsername}"
# Delete role route
- route:
from:
uri: direct:delete-role
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakRoleName
simple: "${body[roleName]}"
- to:
uri: keycloak:admin?operation=deleteRole
- log: "Deleted role: ${header.CamelKeycloakRoleName}"
----
====
=== Client Operations
[tabs]
====
Java::
+
[source,java]
----
// Create a new client
Map<String, Object> clientHeaders = new HashMap<>();
clientHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
clientHeaders.put("CamelKeycloakClientId", "my-service-client");
clientHeaders.put("CamelKeycloakClientSecretRequired", true);
clientHeaders.put("CamelKeycloakClientDirectAccessGrantsEnabled", true);
template.sendBodyAndHeaders("keycloak:admin?operation=createClient", null, clientHeaders);
// Get client information
Map<String, Object> getClientHeaders = new HashMap<>();
getClientHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
getClientHeaders.put("CamelKeycloakClientId", "my-service-client");
template.sendBodyAndHeaders("keycloak:admin?operation=getClient", null, getClientHeaders);
// Get client secret
Map<String, Object> secretHeaders = new HashMap<>();
secretHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
secretHeaders.put("CamelKeycloakClientId", "my-service-client");
String clientSecret = template.requestBodyAndHeaders("keycloak:admin?operation=getClientSecret",
null, secretHeaders, String.class);
// Delete a client
Map<String, Object> deleteClientHeaders = new HashMap<>();
deleteClientHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
deleteClientHeaders.put("CamelKeycloakClientId", "old-client");
template.sendBodyAndHeaders("keycloak:admin?operation=deleteClient", null, deleteClientHeaders);
----
YAML::
+
[source,yaml]
----
# Create client route
- route:
from:
uri: direct:create-client
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientId
simple: "${body[clientId]}"
- setHeader:
name: CamelKeycloakClientSecretRequired
constant: true
- setHeader:
name: CamelKeycloakClientDirectAccessGrantsEnabled
constant: true
- to:
uri: keycloak:admin?operation=createClient
- log: "Created client: ${header.CamelKeycloakClientId}"
# Get client route
- route:
from:
uri: direct:get-client
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientId
simple: "${body[clientId]}"
- to:
uri: keycloak:admin?operation=getClient
- log: "Client info: ${body}"
# Get client secret route
- route:
from:
uri: direct:get-client-secret
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientId
simple: "${body[clientId]}"
- to:
uri: keycloak:admin?operation=getClientSecret
- log: "Client secret retrieved for: ${header.CamelKeycloakClientId}"
# Delete client route
- route:
from:
uri: direct:delete-client
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientId
simple: "${body[clientId]}"
- to:
uri: keycloak:admin?operation=deleteClient
- log: "Deleted client: ${header.CamelKeycloakClientId}"
----
====
=== Group Operations
[tabs]
====
Java::
+
[source,java]
----
// Create a new group
Map<String, Object> groupHeaders = new HashMap<>();
groupHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
groupHeaders.put(KeycloakConstants.GROUP_NAME, "developers");
template.sendBodyAndHeaders("keycloak:admin?operation=createGroup", null, groupHeaders);
// List all groups
template.sendBodyAndHeader("keycloak:admin?operation=listGroups", null,
KeycloakConstants.REALM_NAME, "my-realm");
// Add user to group
Map<String, Object> addToGroupHeaders = new HashMap<>();
addToGroupHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
addToGroupHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
addToGroupHeaders.put(KeycloakConstants.GROUP_ID, "group-id-456");
template.sendBodyAndHeaders("keycloak:admin?operation=addUserToGroup", null, addToGroupHeaders);
// List user's groups
Map<String, Object> userGroupsHeaders = new HashMap<>();
userGroupsHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
userGroupsHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
template.sendBodyAndHeaders("keycloak:admin?operation=listUserGroups", null, userGroupsHeaders);
// Delete a group
Map<String, Object> deleteGroupHeaders = new HashMap<>();
deleteGroupHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
deleteGroupHeaders.put(KeycloakConstants.GROUP_ID, "group-id-456");
template.sendBodyAndHeaders("keycloak:admin?operation=deleteGroup", null, deleteGroupHeaders);
----
YAML::
+
[source,yaml]
----
# Create group route
- route:
from:
uri: direct:create-group
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakGroupName
simple: "${body[groupName]}"
- to:
uri: keycloak:admin?operation=createGroup
- log: "Created group: ${header.CamelKeycloakGroupName}"
# List groups route
- route:
from:
uri: direct:list-groups
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- to:
uri: keycloak:admin?operation=listGroups
- log: "Groups: ${body}"
# Add user to group route
- route:
from:
uri: direct:add-user-to-group
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- setHeader:
name: CamelKeycloakGroupId
simple: "${body[groupId]}"
- to:
uri: keycloak:admin?operation=addUserToGroup
- log: "Added user ${header.CamelKeycloakUserId} to group"
# List user groups route
- route:
from:
uri: direct:list-user-groups
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- to:
uri: keycloak:admin?operation=listUserGroups
- log: "User groups: ${body}"
----
====
=== Password Management Operations
[tabs]
====
Java::
+
[source,java]
----
// Reset user password
Map<String, Object> passwordHeaders = new HashMap<>();
passwordHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
passwordHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
passwordHeaders.put(KeycloakConstants.USER_PASSWORD, "newSecurePassword123!");
passwordHeaders.put(KeycloakConstants.PASSWORD_TEMPORARY, false); // User won't need to change password
template.sendBodyAndHeaders("keycloak:admin?operation=resetUserPassword", null, passwordHeaders);
// Reset with temporary password (user must change on first login)
Map<String, Object> tempPasswordHeaders = new HashMap<>();
tempPasswordHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
tempPasswordHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
tempPasswordHeaders.put(KeycloakConstants.USER_PASSWORD, "tempPassword123");
tempPasswordHeaders.put(KeycloakConstants.PASSWORD_TEMPORARY, true);
template.sendBodyAndHeaders("keycloak:admin?operation=resetUserPassword", null, tempPasswordHeaders);
----
YAML::
+
[source,yaml]
----
# Reset user password route
- route:
from:
uri: direct:reset-password
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- setHeader:
name: CamelKeycloakUserPassword
simple: "${body[password]}"
- setHeader:
name: CamelKeycloakPasswordTemporary
simple: "${body[temporary]}"
- to:
uri: keycloak:admin?operation=resetUserPassword
- log: "Password reset for user ${header.CamelKeycloakUserId}"
# Reset with temporary password
- route:
from:
uri: direct:reset-temp-password
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- setHeader:
name: CamelKeycloakUserPassword
simple: "${body[password]}"
- setHeader:
name: CamelKeycloakPasswordTemporary
constant: true
- to:
uri: keycloak:admin?operation=resetUserPassword
- log: "Temporary password set for user ${header.CamelKeycloakUserId}"
----
====
=== User Search Operations
[tabs]
====
Java::
+
[source,java]
----
// Search users by query
Map<String, Object> searchHeaders = new HashMap<>();
searchHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
searchHeaders.put(KeycloakConstants.SEARCH_QUERY, "john");
template.sendBodyAndHeaders("keycloak:admin?operation=searchUsers", null, searchHeaders);
// Search with pagination
Map<String, Object> paginatedSearchHeaders = new HashMap<>();
paginatedSearchHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
paginatedSearchHeaders.put(KeycloakConstants.SEARCH_QUERY, "doe");
paginatedSearchHeaders.put(KeycloakConstants.FIRST_RESULT, 0);
paginatedSearchHeaders.put(KeycloakConstants.MAX_RESULTS, 10);
template.sendBodyAndHeaders("keycloak:admin?operation=searchUsers", null, paginatedSearchHeaders);
// Get user roles
Map<String, Object> rolesHeaders = new HashMap<>();
rolesHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
rolesHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
List<RoleRepresentation> roles = template.requestBodyAndHeaders(
"keycloak:admin?operation=getUserRoles", null, rolesHeaders, List.class);
----
YAML::
+
[source,yaml]
----
# Search users route
- route:
from:
uri: direct:search-users
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakSearchQuery
simple: "${body[query]}"
- to:
uri: keycloak:admin?operation=searchUsers
- log: "Search results: ${body}"
# Search with pagination
- route:
from:
uri: direct:search-users-paginated
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakSearchQuery
simple: "${body[query]}"
- setHeader:
name: CamelKeycloakFirstResult
simple: "${body[offset]}"
- setHeader:
name: CamelKeycloakMaxResults
simple: "${body[limit]}"
- to:
uri: keycloak:admin?operation=searchUsers
- log: "Found ${body.size} users"
# Get user roles route
- route:
from:
uri: direct:get-user-roles
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- to:
uri: keycloak:admin?operation=getUserRoles
- log: "User roles: ${body}"
----
====
=== Client Role Operations
[tabs]
====
Java::
+
[source,java]
----
// Create client role
Map<String, Object> clientRoleHeaders = new HashMap<>();
clientRoleHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
clientRoleHeaders.put(KeycloakConstants.CLIENT_UUID, "client-uuid-123");
clientRoleHeaders.put(KeycloakConstants.ROLE_NAME, "service-admin");
clientRoleHeaders.put(KeycloakConstants.ROLE_DESCRIPTION, "Service administrator role");
template.sendBodyAndHeaders("keycloak:admin?operation=createClientRole", null, clientRoleHeaders);
// List client roles
Map<String, Object> listClientRolesHeaders = new HashMap<>();
listClientRolesHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
listClientRolesHeaders.put(KeycloakConstants.CLIENT_UUID, "client-uuid-123");
template.sendBodyAndHeaders("keycloak:admin?operation=listClientRoles", null, listClientRolesHeaders);
// Assign client role to user
Map<String, Object> assignClientRoleHeaders = new HashMap<>();
assignClientRoleHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
assignClientRoleHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
assignClientRoleHeaders.put(KeycloakConstants.CLIENT_UUID, "client-uuid-123");
assignClientRoleHeaders.put(KeycloakConstants.ROLE_NAME, "service-admin");
template.sendBodyAndHeaders("keycloak:admin?operation=assignClientRoleToUser", null, assignClientRoleHeaders);
// Remove client role from user
Map<String, Object> removeClientRoleHeaders = new HashMap<>();
removeClientRoleHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
removeClientRoleHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
removeClientRoleHeaders.put(KeycloakConstants.CLIENT_UUID, "client-uuid-123");
removeClientRoleHeaders.put(KeycloakConstants.ROLE_NAME, "service-admin");
template.sendBodyAndHeaders("keycloak:admin?operation=removeClientRoleFromUser", null, removeClientRoleHeaders);
----
YAML::
+
[source,yaml]
----
# Create client role route
- route:
from:
uri: direct:create-client-role
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientUuid
simple: "${body[clientUuid]}"
- setHeader:
name: CamelKeycloakRoleName
simple: "${body[roleName]}"
- setHeader:
name: CamelKeycloakRoleDescription
simple: "${body[description]}"
- to:
uri: keycloak:admin?operation=createClientRole
- log: "Created client role: ${header.CamelKeycloakRoleName}"
# List client roles route
- route:
from:
uri: direct:list-client-roles
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientUuid
simple: "${body[clientUuid]}"
- to:
uri: keycloak:admin?operation=listClientRoles
- log: "Client roles: ${body}"
# Assign client role to user
- route:
from:
uri: direct:assign-client-role
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- setHeader:
name: CamelKeycloakClientUuid
simple: "${body[clientUuid]}"
- setHeader:
name: CamelKeycloakRoleName
simple: "${body[roleName]}"
- to:
uri: keycloak:admin?operation=assignClientRoleToUser
- log: "Assigned client role to user"
----
====
=== Session Management Operations
[tabs]
====
Java::
+
[source,java]
----
// List user sessions
Map<String, Object> sessionsHeaders = new HashMap<>();
sessionsHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
sessionsHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
List<UserSessionRepresentation> sessions = template.requestBodyAndHeaders(
"keycloak:admin?operation=listUserSessions", null, sessionsHeaders, List.class);
// Logout user (invalidate all sessions)
Map<String, Object> logoutHeaders = new HashMap<>();
logoutHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
logoutHeaders.put(KeycloakConstants.USER_ID, "user-id-123");
template.sendBodyAndHeaders("keycloak:admin?operation=logoutUser", null, logoutHeaders);
----
YAML::
+
[source,yaml]
----
# List user sessions route
- route:
from:
uri: direct:list-user-sessions
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- to:
uri: keycloak:admin?operation=listUserSessions
- log: "User sessions: ${body}"
# Logout user route
- route:
from:
uri: direct:logout-user
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakUserId
simple: "${body[userId]}"
- to:
uri: keycloak:admin?operation=logoutUser
- log: "User logged out: ${header.CamelKeycloakUserId}"
----
====
=== Client Scope Operations
[tabs]
====
Java::
+
[source,java]
----
// Create client scope
Map<String, Object> scopeHeaders = new HashMap<>();
scopeHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
scopeHeaders.put(KeycloakConstants.CLIENT_SCOPE_NAME, "custom-scope");
template.sendBodyAndHeaders("keycloak:admin?operation=createClientScope", null, scopeHeaders);
// List client scopes
template.sendBodyAndHeader("keycloak:admin?operation=listClientScopes", null,
KeycloakConstants.REALM_NAME, "my-realm");
// Get client scope
Map<String, Object> getScopeHeaders = new HashMap<>();
getScopeHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
getScopeHeaders.put(KeycloakConstants.CLIENT_SCOPE_ID, "scope-id-123");
template.sendBodyAndHeaders("keycloak:admin?operation=getClientScope", null, getScopeHeaders);
// Delete client scope
Map<String, Object> deleteScopeHeaders = new HashMap<>();
deleteScopeHeaders.put(KeycloakConstants.REALM_NAME, "my-realm");
deleteScopeHeaders.put(KeycloakConstants.CLIENT_SCOPE_ID, "scope-id-123");
template.sendBodyAndHeaders("keycloak:admin?operation=deleteClientScope", null, deleteScopeHeaders);
----
YAML::
+
[source,yaml]
----
# Create client scope route
- route:
from:
uri: direct:create-client-scope
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientScopeName
simple: "${body[scopeName]}"
- to:
uri: keycloak:admin?operation=createClientScope
- log: "Created client scope: ${header.CamelKeycloakClientScopeName}"
# List client scopes route
- route:
from:
uri: direct:list-client-scopes
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- to:
uri: keycloak:admin?operation=listClientScopes
- log: "Client scopes: ${body}"
# Get client scope route
- route:
from:
uri: direct:get-client-scope
steps:
- setHeader:
name: CamelKeycloakRealmName
constant: "my-realm"
- setHeader:
name: CamelKeycloakClientScopeId
simple: "${body[scopeId]}"
- to:
uri: keycloak:admin?operation=getClientScope
- log: "Client scope: ${body}"
----
====
=== Complete Producer Example
[tabs]
====
Java::
+
[source,java]
----
public class KeycloakManagementRoutes extends RouteBuilder {
@Override
public void configure() throws Exception {
// Configure Keycloak component
KeycloakComponent keycloak = getContext().getComponent("keycloak", KeycloakComponent.class);
KeycloakConfiguration config = new KeycloakConfiguration();
config.setServerUrl("http://localhost:8080");
config.setRealm("master");
config.setUsername("admin");
config.setPassword("admin");
keycloak.setConfiguration(config);
// Comprehensive user management route
from("direct:setup-user-environment")
.routeId("setup-user-environment")
.log("Setting up user environment...")
// Step 1: Create realm
.setHeader(KeycloakConstants.REALM_NAME, constant("my-company"))
.to("keycloak:admin?operation=createRealm")
.log("Created realm: my-company")
// Step 2: Create roles
.setHeader(KeycloakConstants.ROLE_NAME, constant("admin"))
.setHeader(KeycloakConstants.ROLE_DESCRIPTION, constant("Administrator role"))
.to("keycloak:admin?operation=createRole")
.log("Created admin role")
.setHeader(KeycloakConstants.ROLE_NAME, constant("user"))
.setHeader(KeycloakConstants.ROLE_DESCRIPTION, constant("Standard user role"))
.to("keycloak:admin?operation=createRole")
.log("Created user role")
// Step 3: Create client
.setHeader("CamelKeycloakClientId", constant("my-app"))
.setHeader("CamelKeycloakClientSecretRequired", constant(true))
.setHeader("CamelKeycloakClientDirectAccessGrantsEnabled", constant(true))
.to("keycloak:admin?operation=createClient")
.log("Created client: my-app")
// Step 4: Create users
.setHeader(KeycloakConstants.USERNAME, constant("admin.user"))
.setHeader(KeycloakConstants.USER_EMAIL, constant("admin@company.com"))
.setHeader(KeycloakConstants.USER_FIRST_NAME, constant("Admin"))
.setHeader(KeycloakConstants.USER_LAST_NAME, constant("User"))
.to("keycloak:admin?operation=createUser")
.log("Created admin user")
// Step 5: Set password
.setHeader("CamelKeycloakUserPassword", constant("admin123"))
.setHeader("CamelKeycloakUserPasswordTemporary", constant(false))
.to("keycloak:admin?operation=setUserPassword")
.log("Set admin user password")
// Step 6: Assign role
.setHeader(KeycloakConstants.ROLE_NAME, constant("admin"))
.to("keycloak:admin?operation=assignRoleToUser")
.log("Assigned admin role to user")
.transform().constant("User environment setup completed successfully");
// User management API routes
from("rest:post:/users")
.routeId("create-user-api")
.log("Creating user: ${body}")
.setHeader(KeycloakConstants.REALM_NAME, constant("my-company"))
.setHeader(KeycloakConstants.USERNAME, jsonpath("$.username"))
.setHeader(KeycloakConstants.USER_EMAIL, jsonpath("$.email"))
.setHeader(KeycloakConstants.USER_FIRST_NAME, jsonpath("$.firstName"))
.setHeader(KeycloakConstants.USER_LAST_NAME, jsonpath("$.lastName"))
.to("keycloak:admin?operation=createUser")
.setHeader("Content-Type", constant("application/json"))
.transform().constant("{\"status\": \"success\", \"message\": \"User created\"}");
from("rest:get:/users")
.routeId("list-users-api")
.log("Listing users")
.setHeader(KeycloakConstants.REALM_NAME, constant("my-company"))
.to("keycloak:admin?operation=listUsers")
.setHeader("Content-Type", constant("application/json"));
from("rest:delete:/users/{username}")
.routeId("delete-user-api")
.log("Deleting user: ${header.username}")
.setHeader(KeycloakConstants.REALM_NAME, constant("my-company"))
.setHeader(KeycloakConstants.USERNAME, header("username"))
.to("keycloak:admin?operation=deleteUser")
.setHeader("Content-Type", constant("application/json"))
.transform().constant("{\"status\": \"success\", \"message\": \"User deleted\"}");
}
}
----
YAML::
+
[source,yaml]
----
# Complete Keycloak producer configuration
- route:
id: setup-user-environment
from:
uri: direct:setup-user-environment
steps:
- log: "Setting up user environment..."
# Step 1: Create realm
- setHeader:
name: CamelKeycloakRealmName
constant: "my-company"
- to:
uri: keycloak:admin?operation=createRealm
- log: "Created realm: my-company"
# Step 2: Create admin role
- setHeader:
name: CamelKeycloakRoleName
constant: "admin"
- setHeader:
name: CamelKeycloakRoleDescription
constant: "Administrator role"
- to:
uri: keycloak:admin?operation=createRole
- log: "Created admin role"
# Step 3: Create user role
- setHeader:
name: CamelKeycloakRoleName
constant: "user"
- setHeader:
name: CamelKeycloakRoleDescription
constant: "Standard user role"
- to:
uri: keycloak:admin?operation=createRole
- log: "Created user role"
# Step 4: Create client
- setHeader:
name: CamelKeycloakClientId
constant: "my-app"
- setHeader:
name: CamelKeycloakClientSecretRequired
constant: true
- setHeader:
name: CamelKeycloakClientDirectAccessGrantsEnabled
constant: true
- to:
uri: keycloak:admin?operation=createClient
- log: "Created client: my-app"
# Step 5: Create admin user
- setHeader:
name: CamelKeycloakUsername
constant: "admin.user"
- setHeader:
name: CamelKeycloakUserEmail
constant: "admin@company.com"
- setHeader:
name: CamelKeycloakUserFirstName
constant: "Admin"
- setHeader:
name: CamelKeycloakUserLastName
constant: "User"
- to:
uri: keycloak:admin?operation=createUser
- log: "Created admin user"
# Step 6: Set password
- setHeader:
name: CamelKeycloakUserPassword
constant: "admin123"
- setHeader:
name: CamelKeycloakUserPasswordTemporary
constant: false
- to:
uri: keycloak:admin?operation=setUserPassword
- log: "Set admin user password"
# Step 7: Assign role
- setHeader:
name: CamelKeycloakRoleName
constant: "admin"
- to:
uri: keycloak:admin?operation=assignRoleToUser
- log: "Assigned admin role to user"
- transform:
constant: "User environment setup completed successfully"
# REST API routes for user management
- rest:
path: /users
post:
- to: direct:create-user-api
- rest:
path: /users
get:
- to: direct:list-users-api
- rest:
path: /users/{username}
delete:
- to: direct:delete-user-api
# Route implementations
- route:
id: create-user-api
from:
uri: direct:create-user-api
steps:
- log: "Creating user: ${body}"
- setHeader:
name: CamelKeycloakRealmName
constant: "my-company"
- setHeader:
name: CamelKeycloakUsername
jsonpath: "$.username"
- setHeader:
name: CamelKeycloakUserEmail
jsonpath: "$.email"
- setHeader:
name: CamelKeycloakUserFirstName
jsonpath: "$.firstName"
- setHeader:
name: CamelKeycloakUserLastName
jsonpath: "$.lastName"
- to:
uri: keycloak:admin?operation=createUser
- setHeader:
name: Content-Type
constant: "application/json"
- transform:
constant: '{"status": "success", "message": "User created"}'
- route:
id: list-users-api
from:
uri: direct:list-users-api
steps:
- log: "Listing users"
- setHeader:
name: CamelKeycloakRealmName
constant: "my-company"
- to:
uri: keycloak:admin?operation=listUsers
- setHeader:
name: Content-Type
constant: "application/json"
- route:
id: delete-user-api
from:
uri: direct:delete-user-api
steps:
- log: "Deleting user: ${header.username}"
- setHeader:
name: CamelKeycloakRealmName
constant: "my-company"
- setHeader:
name: CamelKeycloakUsername
header: "username"
- to:
uri: keycloak:admin?operation=deleteUser
- setHeader:
name: Content-Type
constant: "application/json"
- transform:
constant: '{"status": "success", "message": "User deleted"}'
# Component configuration
camel:
component:
keycloak:
server-url: "http://localhost:8080"
realm: "master"
username: "admin"
password: "admin"
----
====
== Security Policies
The Keycloak security policy provides route-level authorization using Keycloak authentication and authorization services.
== Features
The Keycloak security policy supports:
* **Role-based authorization** - Validate user roles from Keycloak tokens
* **Permission-based authorization** - Validate fine-grained permissions using Keycloak Authorization Services
* **Token validation** - Verify access tokens from Keycloak
* **Flexible configuration** - Support for client credentials and resource owner password flows
== Configuration
=== Basic Setup
[tabs]
====
Java::
+
[source,java]
----
KeycloakSecurityPolicy policy = new KeycloakSecurityPolicy();
policy.setServerUrl("http://localhost:8080");
policy.setRealm("my-realm");
policy.setClientId("my-client");
policy.setClientSecret("my-client-secret");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:start
steps:
- policy:
ref: keycloakPolicy
- to:
uri: mock:result
# Bean definition in beans configuration
beans:
- name: keycloakPolicy
type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
properties:
serverUrl: "http://localhost:8080"
realm: "my-realm"
clientId: "my-client"
clientSecret: "my-client-secret"
----
====
=== Role-based Authorization
[tabs]
====
Java::
+
[source,java]
----
KeycloakSecurityPolicy policy = new KeycloakSecurityPolicy(
"http://localhost:8080", "my-realm", "my-client", "client-secret");
// Require specific roles
policy.setRequiredRoles(Arrays.asList("admin", "user"));
policy.setAllRolesRequired(true); // User must have ALL roles
from("direct:admin")
.policy(policy)
.to("mock:admin-endpoint");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:admin
steps:
- policy:
ref: adminPolicy
- to:
uri: mock:admin-endpoint
# Bean definition
beans:
- name: adminPolicy
type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
properties:
serverUrl: "http://localhost:8080"
realm: "my-realm"
clientId: "my-client"
clientSecret: "client-secret"
requiredRoles:
- "admin"
- "user"
allRolesRequired: true
----
====
=== Permission-based Authorization
[tabs]
====
Java::
+
[source,java]
----
KeycloakSecurityPolicy policy = new KeycloakSecurityPolicy(
"http://localhost:8080", "my-realm", "my-client", "client-secret");
// Require specific permissions
policy.setRequiredPermissions(Arrays.asList("read:documents", "write:documents"));
policy.setAllPermissionsRequired(false); // User needs ANY permission
from("direct:documents")
.policy(policy)
.to("mock:documents-endpoint");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:documents
steps:
- policy:
ref: documentsPolicy
- to:
uri: mock:documents-endpoint
# Bean definition
beans:
- name: documentsPolicy
type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
properties:
serverUrl: "http://localhost:8080"
realm: "my-realm"
clientId: "my-client"
clientSecret: "client-secret"
requiredPermissions:
- "read:documents"
- "write:documents"
allPermissionsRequired: false
----
====
=== Resource Owner Password Credentials
[tabs]
====
Java::
+
[source,java]
----
KeycloakSecurityPolicy policy = new KeycloakSecurityPolicy(
"http://localhost:8080", "my-realm", "my-client", "username", "password");
from("direct:user-flow")
.policy(policy)
.to("mock:result");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:user-flow
steps:
- policy:
ref: userFlowPolicy
- to:
uri: mock:result
# Bean definition
beans:
- name: userFlowPolicy
type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
properties:
serverUrl: "http://localhost:8080"
realm: "my-realm"
clientId: "my-client"
username: "username"
password: "password"
useResourceOwnerPasswordCredentials: true
----
====
== Usage
=== Providing Access Tokens
The security policy expects access tokens to be provided in one of the following ways:
1. **Header**: `CamelKeycloakAccessToken`
2. **Authorization Header**: `Authorization: Bearer <token>`
3. **Exchange Property**: `CamelKeycloakAccessToken`
[source,java]
----
// Using header
template.sendBodyAndHeader("direct:protected", "message",
KeycloakSecurityConstants.ACCESS_TOKEN_HEADER, accessToken);
// Using Authorization header
template.sendBodyAndHeader("direct:protected", "message",
"Authorization", "Bearer " + accessToken);
----
=== Route Examples
[tabs]
====
Java::
+
[source,java]
----
from("direct:admin-only")
.policy(adminPolicy)
.transform().constant("Admin access granted")
.to("mock:admin");
from("direct:user-or-admin")
.policy(userPolicy)
.transform().constant("User access granted")
.to("mock:user");
from("rest:get:/api/documents")
.policy(documentsPolicy)
.to("direct:list-documents");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:admin-only
steps:
- policy:
ref: adminPolicy
- transform:
constant: "Admin access granted"
- to:
uri: mock:admin
- route:
from:
uri: direct:user-or-admin
steps:
- policy:
ref: userPolicy
- transform:
constant: "User access granted"
- to:
uri: mock:user
- rest:
get:
- uri: /api/documents
to: direct:list-documents
route:
policy:
ref: documentsPolicy
----
====
== Configuration Options
[width="100%",cols="10%,10%,80%",options="header"]
|===
| Name | Default | Description
| serverUrl | | Keycloak server URL (e.g., http://localhost:8080)
| realm | | Keycloak realm name
| clientId | | Keycloak client ID
| clientSecret | | Keycloak client secret (for client credentials flow)
| username | | Username (for resource owner password flow)
| password | | Password (for resource owner password flow)
| requiredRoles | [] | List of required roles
| requiredPermissions | [] | List of required permissions
| allRolesRequired | true | Whether ALL roles are required (true) or ANY role (false)
| allPermissionsRequired | true | Whether ALL permissions are required (true) or ANY permission (false)
| useResourceOwnerPasswordCredentials | false | Whether to use resource owner password flow
|===
== Security Considerations
* Always use HTTPS in production environments
* Store client secrets securely (environment variables, secret management systems)
* Regularly rotate client secrets and user passwords
* Use the principle of least privilege when assigning roles and permissions
* Consider token expiration and refresh strategies
== Error Handling
The component throws `CamelAuthorizationException` when:
* Access token is missing or invalid
* User doesn't have required roles
* User doesn't have required permissions
* Keycloak server is unreachable
* Token verification fails
[tabs]
====
Java::
+
[source,java]
----
onException(CamelAuthorizationException.class)
.handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
.transform().constant("Access denied");
----
YAML::
+
[source,yaml]
----
- onException:
exception:
- "org.apache.camel.CamelAuthorizationException"
handled: true
steps:
- setHeader:
name: "CamelHttpResponseCode"
constant: 403
- transform:
constant: "Access denied"
----
====
== Examples
=== Basic Role-based Authorization
[tabs]
====
Java::
+
[source,java]
----
// Create Keycloak security policy
KeycloakSecurityPolicy keycloakPolicy = new KeycloakSecurityPolicy();
keycloakPolicy.setServerUrl("http://localhost:8080");
keycloakPolicy.setRealm("my-company");
keycloakPolicy.setClientId("my-service");
keycloakPolicy.setClientSecret("client-secret-value");
// Require admin role
keycloakPolicy.setRequiredRoles(Arrays.asList("admin"));
// Apply to route
from("direct:admin-endpoint")
.policy(keycloakPolicy)
.transform().constant("Admin access granted")
.to("mock:admin-result");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:admin-endpoint
steps:
- policy:
ref: keycloakPolicy
- transform:
constant: "Admin access granted"
- to:
uri: mock:admin-result
# Bean definition
beans:
- name: keycloakPolicy
type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
properties:
serverUrl: "http://localhost:8080"
realm: "my-company"
clientId: "my-service"
clientSecret: "client-secret-value"
requiredRoles:
- "admin"
----
====
=== Multiple Role Authorization
[tabs]
====
Java::
+
[source,java]
----
// Require either admin OR user role
KeycloakSecurityPolicy userPolicy = new KeycloakSecurityPolicy(
"http://localhost:8080", "my-company", "my-service", "client-secret");
userPolicy.setRequiredRoles(Arrays.asList("admin", "user"));
userPolicy.setAllRolesRequired(false); // ANY role (OR logic)
from("direct:user-endpoint")
.policy(userPolicy)
.to("bean:userService?method=processUser");
----
YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:user-endpoint
steps:
- policy:
ref: userPolicy
- to:
uri: bean:userService?method=processUser
# Bean definition
beans:
- name: userPolicy
type: org.apache.camel.component.keycloak.security.KeycloakSecurityPolicy
properties:
serverUrl: "http://localhost:8080"
realm: "my-company"
clientId: "my-service"
clientSecret: "client-secret"
requiredRoles:
- "admin"
- "user"
allRolesRequired: false
----
====
=== REST API with Keycloak Protection
[tabs]
====
Java::
+
[source,java]
----
// Configure different policies for different endpoints
KeycloakSecurityPolicy readPolicy = new KeycloakSecurityPolicy(
"{{keycloak.server-url}}", "{{keycloak.realm}}",
"{{keycloak.client-id}}", "{{keycloak.client-secret}}");
readPolicy.setRequiredRoles(Arrays.asList("reader", "writer", "admin"));
readPolicy.setAllRolesRequired(false);
KeycloakSecurityPolicy writePolicy = new KeycloakSecurityPolicy(
"{{keycloak.server-url}}", "{{keycloak.realm}}",
"{{keycloak.client-id}}", "{{keycloak.client-secret}}");
writePolicy.setRequiredRoles(Arrays.asList("writer", "admin"));
writePolicy.setAllRolesRequired(false);
KeycloakSecurityPolicy adminPolicy = new KeycloakSecurityPolicy(
"{{keycloak.server-url}}", "{{keycloak.realm}}",
"{{keycloak.client-id}}", "{{keycloak.client-secret}}");
adminPolicy.setRequiredRoles(Arrays.asList("admin"));
// Configure REST endpoints
rest("/api")
.get("/documents")
.route()
.policy(readPolicy)
.to("bean:documentService?method=listDocuments")
.endRest()
.post("/documents")
.route()
.policy(writePolicy)
.to("bean:documentService?method=createDocument")
.endRest()
.delete("/documents/{id}")
.route()
.policy(adminPolicy)
.to("bean:documentService?method=deleteDocument")
.endRest();
----
YAML::
+
[source,yaml]
----
- rest:
path: "/api"
get:
- uri: "/documents"
to: bean:documentService?method=listDocuments
route:
policy:
ref: readPolicy
post:
- uri: "/documents"
to: bean:documentService?method=createDocument
route:
policy:
ref: writePolicy
delete:
- uri: "/documents/{id}"
to: bean:documentService?method=deleteDocument
route:
policy:
ref: adminPolicy
# Bean definitions for policies
beans:
- name: readPolicy
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:
- "reader"
- "writer"
- "admin"
allRolesRequired: false
- name: writePolicy
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:
- "writer"
- "admin"
allRolesRequired: false
- name: adminPolicy
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"
----
====
=== Sending Requests with Tokens
[source,java]
----
// In your client code, include the access token
String accessToken = "eyJhbGciOiJSUzI1NiIsInR5cC..."; // From Keycloak
// Option 1: Using custom header
template.sendBodyAndHeader("direct:protected-endpoint",
requestBody,
KeycloakSecurityConstants.ACCESS_TOKEN_HEADER,
accessToken);
// Option 2: Using Authorization header (standard)
template.sendBodyAndHeader("direct:protected-endpoint",
requestBody,
"Authorization",
"Bearer " + accessToken);
// Option 3: Using exchange property
Exchange exchange = ExchangeBuilder.anExchange(camelContext)
.withBody(requestBody)
.withProperty(KeycloakSecurityConstants.ACCESS_TOKEN_PROPERTY, accessToken)
.build();
template.send("direct:protected-endpoint", exchange);
----
=== Advanced Error Handling
[tabs]
====
Java::
+
[source,java]
----
// Global error handler for authorization failures
onException(CamelAuthorizationException.class)
.handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
.setHeader("Content-Type", constant("application/json"))
.transform().constant("{\"error\": \"Access denied\", \"message\": \"Insufficient privileges\"}")
.log("Authorization failed: ${exception.message}");
// Route-specific error handling
from("rest:post:/secure-data")
.doTry()
.policy(keycloakPolicy)
.to("bean:dataProcessor")
.doCatch(CamelAuthorizationException.class)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
.transform().constant("Access denied")
.end();
----
YAML::
+
[source,yaml]
----
# Global error handler
- onException:
exception:
- "org.apache.camel.CamelAuthorizationException"
handled: true
steps:
- setHeader:
name: "CamelHttpResponseCode"
constant: 403
- setHeader:
name: "Content-Type"
constant: "application/json"
- transform:
constant: '{"error": "Access denied", "message": "Insufficient privileges"}'
- log: "Authorization failed: ${exception.message}"
# Route-specific error handling
- route:
from:
uri: rest:post:/secure-data
steps:
- doTry:
steps:
- policy:
ref: keycloakPolicy
- to:
uri: bean:dataProcessor
doCatch:
- exception:
- "org.apache.camel.CamelAuthorizationException"
steps:
- setHeader:
name: "CamelHttpResponseCode"
constant: 403
- transform:
constant: "Access denied"
----
====
=== Configuration Properties
[tabs]
====
Properties::
+
[source,properties]
----
# application.properties
keycloak.server-url=http://localhost:8080
keycloak.realm=my-company
keycloak.client-id=my-service
keycloak.client-secret=your-client-secret
----
=== Spring Configuration
[source,java]
----
@Configuration
public class SecurityConfiguration {
@Value("${keycloak.server-url}")
private String serverUrl;
@Value("${keycloak.realm}")
private String realm;
@Value("${keycloak.client-id}")
private String clientId;
@Value("${keycloak.client-secret}")
private String clientSecret;
@Bean
public KeycloakSecurityPolicy adminPolicy() {
KeycloakSecurityPolicy policy = new KeycloakSecurityPolicy(
serverUrl, realm, clientId, clientSecret);
policy.setRequiredRoles(Arrays.asList("admin"));
return policy;
}
@Bean
public KeycloakSecurityPolicy userPolicy() {
KeycloakSecurityPolicy policy = new KeycloakSecurityPolicy(
serverUrl, realm, clientId, clientSecret);
policy.setRequiredRoles(Arrays.asList("user", "admin"));
policy.setAllRolesRequired(false);
return policy;
}
}
----
=== Complete Route Configuration
[tabs]
====
Java::
+
[source,java]
----
public class KeycloakSecurityRoutes extends RouteBuilder {
@Override
public void configure() throws Exception {
// Admin policy - requires admin role
KeycloakSecurityPolicy adminPolicy = new KeycloakSecurityPolicy(
"{{keycloak.server-url}}", "{{keycloak.realm}}",
"{{keycloak.client-id}}", "{{keycloak.client-secret}}");
adminPolicy.setRequiredRoles(Arrays.asList("admin"));
// User policy - requires user or admin role
KeycloakSecurityPolicy userPolicy = new KeycloakSecurityPolicy(
"{{keycloak.server-url}}", "{{keycloak.realm}}",
"{{keycloak.client-id}}", "{{keycloak.client-secret}}");
userPolicy.setRequiredRoles(Arrays.asList("user", "admin"));
userPolicy.setAllRolesRequired(false); // ANY role
// Error handling
onException(CamelAuthorizationException.class)
.handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(403))
.transform().constant("Forbidden");
// Routes
from("rest:get:/admin/users")
.policy(adminPolicy)
.to("bean:userService?method=getAllUsers");
from("rest:get:/profile")
.policy(userPolicy)
.to("bean:userService?method=getCurrentUser");
}
}
----
YAML::
+
[source,yaml]
----
# Complete route configuration with Keycloak security
- onException:
exception:
- "org.apache.camel.CamelAuthorizationException"
handled: true
steps:
- setHeader:
name: "CamelHttpResponseCode"
constant: 403
- transform:
constant: "Forbidden"
- route:
from:
uri: rest:get:/admin/users
steps:
- policy:
ref: adminPolicy
- to:
uri: bean:userService?method=getAllUsers
- route:
from:
uri: rest:get:/profile
steps:
- policy:
ref: userPolicy
- to:
uri: bean:userService?method=getCurrentUser
# Security policy beans
beans:
- name: adminPolicy
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"
- name: userPolicy
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:
- "user"
- "admin"
allRolesRequired: false
----
== Running Integration Tests
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
[source,bash]
----
# Start Keycloak in development mode
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:latest start-dev
----
==== 2. Access Keycloak Admin Console
Open your browser to http://localhost:8080/admin and login with:
- Username: `admin`
- Password: `admin`
=== Keycloak Configuration for Integration Tests
==== 3. Create Test Realm
1. In the Keycloak Admin Console, click **"Add realm"**
2. Set realm name to: `test-realm`
3. Click **"Create"**
==== 4. Create Test Client
1. In the `test-realm`, go to **Clients** **"Create client"**
2. Set the following:
- Client type: `OpenID Connect`
- Client ID: `test-client`
- Next Client authentication: `ON`
- Authorization: `ON` (optional, for advanced features)
- Next Valid redirect URIs: `*`
- Click **"Save"**
3. Go to **Credentials** tab and copy the **Client Secret**
==== 5. Create Test Roles
1. Go to **Realm roles** **"Create role"**
2. Create the following roles:
- `admin-role`
- `user`
- `reader`
==== 6. Create Test Users
Create three test users with the following configuration:
**User 1: myuser**
1. Go to **Users** **"Add user"**
2. Set:
- Username: `myuser`
- Email: `myuser@test.com`
- First name: `My`
- Last name: `User`
- Click **"Create"**
3. Go to **Credentials** tab **"Set password"**
- Password: `pippo123`
- Temporary: `OFF`
4. Go to **Role mapping** tab **"Assign role"**
- Assign role: `admin-role`
**User 2: test-user**
1. Create user with:
- Username: `test-user`
- Password: `user123` (temporary: OFF)
- Assign role: `user`
**User 3: reader-user**
1. Create user with:
- Username: `reader-user`
- Password: `reader123` (temporary: OFF)
- Assign role: `reader`
=== Running the Integration Tests
==== 7. Execute Tests with Maven
**Run All Integration Tests:**
[source,bash]
----
# Run integration tests with required properties
mvn test -Dtest=KeycloakSecurityIT \
-Dkeycloak.server.url=http://localhost:8080 \
-Dkeycloak.realm=test-realm \
-Dkeycloak.client.id=test-client \
-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
[source,bash]
----
export KEYCLOAK_SERVER_URL=http://localhost:8080
export KEYCLOAK_REALM=test-realm
export KEYCLOAK_CLIENT_ID=test-client
export KEYCLOAK_CLIENT_SECRET=YOUR_CLIENT_SECRET
# Run tests
mvn test -Dtest=KeycloakSecurityIT \
-Dkeycloak.server.url=$KEYCLOAK_SERVER_URL \
-Dkeycloak.realm=$KEYCLOAK_REALM \
-Dkeycloak.client.id=$KEYCLOAK_CLIENT_ID \
-Dkeycloak.client.secret=$KEYCLOAK_CLIENT_SECRET
----
=== Troubleshooting
**Tests are skipped**: Verify all four required properties are provided and Keycloak is running on the specified URL.
**401 Unauthorized**: Check that:
- Users exist with correct passwords
- Users have the required roles assigned
- Client credentials are correct
**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
----
====