This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch kafka-apicurio-json-schema
in repository https://gitbox.apache.org/repos/asf/camel-kamelets-examples.git

commit 47ba14ad3f7e267766fc7b4264efac01eb954374
Author: Andrea Cosentino <anco...@gmail.com>
AuthorDate: Wed May 15 10:02:31 2024 +0200

    Added an example of Kafka + Apicurio Registry secured with Keycloak and 
Json Schema validation
    
    Signed-off-by: Andrea Cosentino <anco...@gmail.com>
---
 .../README.md                                      |  180 ++
 .../application.properties                         |    9 +
 .../docker-compose/config-registry.yml             |   56 +
 .../config/keycloak/apicurio-realm.json            | 2235 ++++++++++++++++++++
 .../docker-compose/config/prometheus.yml           |    6 +
 .../config/provisioning/datasources/datasource.yml |   12 +
 .../kafka-apicurio-kamelet.camel.yaml              |   41 +
 ...ured-apicurio-registry-json-source.kamelet.yaml |  188 ++
 .../kafka-producer/pom.xml                         |   60 +
 .../main/java/com/acme/example/kafka/Produce.java  |   92 +
 .../com/acme/example/kafka/models/Product.java     |   37 +
 .../acme/example/kafka/models/WrongProduct.java    |   46 +
 12 files changed, 2962 insertions(+)

diff --git a/jbang/kafka-apicurio-secured-json-schema-registry/README.md 
b/jbang/kafka-apicurio-secured-json-schema-registry/README.md
new file mode 100644
index 0000000..854f9be
--- /dev/null
+++ b/jbang/kafka-apicurio-secured-json-schema-registry/README.md
@@ -0,0 +1,180 @@
+# Example for consuming from Kafka with the usage of Apicurio Schema Registry 
secured with Keycloak and JSON Schema
+
+You'll need a running Kafka instance and an Apicurio Registry
+
+## Kafka instance
+
+You could use a plain Kafka archive or use an Ansible role
+
+## Apicurio Registry settings
+
+In the `docker-compose` folder run
+
+```bash
+docker-compose -f config-registry.yml up
+```
+
+This will bring up the required bits for making an Apicurio Registry secured 
with Keycloak up and running.
+
+Once everything is up and running, access the Keycloak instance located at 
http://YOUR_IP:8080
+
+The username and password is admin/admin.
+
+Select the realm registry and create a new user called registry-account with 
password registry.
+
+The client Id from Keycloak will be registry-api.
+
+In the client page, select credentials and copy the client secret value.
+
+In application.properties file copy the client secret value into 
keycloak.client.secret.
+
+The rest of the options could be used as-is.
+
+### Adding the JSON Schema
+
+The Apicurio Registry doesn't support the auto creation of artifacts for Json 
Schema so you'll have to create it by hand.
+
+Open a browser and point to http://YOUR_IP:8081/ui/
+
+In the artifacts section select upload artifact
+
+For the group the input will be "default"
+
+For the artifact id the input will be "product-topic-value", since we are 
pointing to a product-topic topic.
+
+For the type the input will be "JSON Schema"
+
+In the artifact section insert the following Schema
+
+```json
+{
+  "$schema": "http://json-schema.org/draft-04/schema#";,
+  "title": "Product",
+  "description": "A product from Acme's catalog",
+  "type": "object",
+  "properties": {
+    "id": {
+      "description": "The unique identifier for a product",
+      "type": "integer"
+    },
+    "name": {
+      "description": "Name of the product",
+      "type": "string"
+    }
+  },
+  "required": [
+    "id",
+    "name"
+  ]
+}
+```
+
+Now click "upload" and the Json Schema will be uploaded and the artifact will 
be ready to use.
+
+## Configure the applications
+
+In `application.properties` set the Kafka instance address.
+
+## Produce to Kafka.
+
+Run 
[`Produce.java`](./kafka-producer/src/main/java/com/acme/example/kafka/Produce.java)
 to produce a message to the Kafka.
+
+```bash
+mvn compile exec:java -Dexec.mainClass="com.acme.example.kafka.Produce"
+```
+
+```bash
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.clients.producer.KafkaProducer - [Producer 
clientId=producer-1] Instantiated an idempotent producer.
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.clients.producer.ProducerConfig - These configurations 
'[apicurio.registry.auto-register, keycloak.client.secret, keycloak.realm, 
keycloak.client.id, apicurio.auth.client.id, keycloak.apicurio.username, 
apicurio.auth.client.secret, apicurio.auth.service.url, schema.registry.url, 
apicurio.registry.url, apicurio.auth.realm, keycloak.apicurio.password, topic, 
apicurio.auth.username, keycloak.service.url, apicurio.auth.password]'  [...]
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.common.utils.AppInfoParser - Kafka version: 3.5.1
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.common.utils.AppInfoParser - Kafka commitId: 2c6fb6c54472e90a
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.common.utils.AppInfoParser - Kafka startTimeMs: 1715758646947
+[kafka-producer-network-thread | producer-1] INFO 
org.apache.kafka.clients.Metadata - [Producer clientId=producer-1] Cluster ID: 
cQJRW1YgSxubt8WdH4p2Tw
+[kafka-producer-network-thread | producer-1] INFO 
org.apache.kafka.clients.producer.internals.TransactionManager - [Producer 
clientId=producer-1] ProducerId set to 21 with epoch 0
+Sent record with offset 0
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.clients.producer.KafkaProducer - [Producer 
clientId=producer-1] Closing the Kafka producer with timeoutMillis = 
9223372036854775807 ms.
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.common.metrics.Metrics - Metrics scheduler closed
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.common.metrics.Metrics - Closing reporter 
org.apache.kafka.common.metrics.JmxReporter
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.common.metrics.Metrics - Metrics reporters closed
+[com.acme.example.kafka.Produce.main()] INFO 
org.apache.kafka.common.utils.AppInfoParser - App info kafka.producer for 
producer-1 unregistered
+[WARNING] 
+java.io.UncheckedIOException: java.io.IOException: Error validating data 
against json schema with message: $: requested property 'id' not found $: 
requested property 'name' not found
+    at io.apicurio.registry.serde.AbstractKafkaSerializer.serialize 
(AbstractKafkaSerializer.java:96)
+    at org.apache.kafka.clients.producer.KafkaProducer.doSend 
(KafkaProducer.java:1015)
+    at org.apache.kafka.clients.producer.KafkaProducer.send 
(KafkaProducer.java:962)
+    at org.apache.kafka.clients.producer.KafkaProducer.send 
(KafkaProducer.java:847)
+    at com.acme.example.kafka.Produce.main (Produce.java:86)
+    at org.codehaus.mojo.exec.ExecJavaMojo.lambda$execute$0 
(ExecJavaMojo.java:283)
+    at java.lang.Thread.run (Thread.java:833)
+Caused by: java.io.IOException: Error validating data against json schema with 
message: $: requested property 'id' not found $: requested property 'name' not 
found
+    at 
io.apicurio.registry.serde.jsonschema.JsonSchemaValidationUtil.validateDataWithSchema
 (JsonSchemaValidationUtil.java:45)
+    at 
io.apicurio.registry.serde.jsonschema.JsonSchemaKafkaSerializer.serializeData 
(JsonSchemaKafkaSerializer.java:138)
+    at io.apicurio.registry.serde.AbstractKafkaSerializer.serialize 
(AbstractKafkaSerializer.java:88)
+    at org.apache.kafka.clients.producer.KafkaProducer.doSend 
(KafkaProducer.java:1015)
+    at org.apache.kafka.clients.producer.KafkaProducer.send 
(KafkaProducer.java:962)
+    at org.apache.kafka.clients.producer.KafkaProducer.send 
(KafkaProducer.java:847)
+    at com.acme.example.kafka.Produce.main (Produce.java:86)
+    at org.codehaus.mojo.exec.ExecJavaMojo.lambda$execute$0 
(ExecJavaMojo.java:283)
+    at java.lang.Thread.run (Thread.java:833)
+```
+
+The first record will work because the validation will be passed, the second 
one won't pass, since the record is an instance of the class WrongProduct 
instead of Product.
+
+
+## Produce to Kafka without Kamelets
+
+To consume messages using a Camel route, first install the kafka-producer 
maven project:
+```bash
+cd kafka-producer
+mvn clean install
+```
+
+then run:
+```bash
+jbang run camel@apache/camel run --properties=application.properties 
--local-kamelet-dir=. kafka-apicurio-kamelet.camel.yaml
+```
+
+You should see something like
+
+```bash
+2024-05-15 09:36:38.372  INFO 24390 --- [           main] 
e.camel.impl.engine.AbstractCamelContext : Routes startup (total:1 started:1 
kamelets:2)
+2024-05-15 09:36:38.372  INFO 24390 --- [           main] 
e.camel.impl.engine.AbstractCamelContext :     Started kafka-to-apicurio-log 
(kamelet://kafka-not-secured-apicurio-registry-json-source)
+2024-05-15 09:36:38.373  INFO 24390 --- [           main] 
e.camel.impl.engine.AbstractCamelContext : Apache Camel 4.6.0 
(kafka-apicurio-kamelet) started in 217ms (build:0ms init:0ms start:217ms)
+2024-05-15 09:36:38.669  INFO 24390 --- [[product-topic]] 
he.kafka.clients.consumer.ConsumerConfig : These configurations 
'[retry.backoff.max.ms, apicurio.registry.avroDatumProvider, 
apicurio.auth.service.url, apicurio.auth.realm, apicurio.auth.password, 
apicurio.auth.client.id, apicurio.auth.client.secret, apicurio.registry.url, 
apicurio.auth.username]' were supplied but are not used yet.
+2024-05-15 09:36:38.670  INFO 24390 --- [[product-topic]] 
.apache.kafka.common.utils.AppInfoParser : Kafka version: 3.5.1
+2024-05-15 09:36:38.670  INFO 24390 --- [[product-topic]] 
.apache.kafka.common.utils.AppInfoParser : Kafka commitId: 2c6fb6c54472e90a
+2024-05-15 09:36:38.670  INFO 24390 --- [[product-topic]] 
.apache.kafka.common.utils.AppInfoParser : Kafka startTimeMs: 1715758598669
+2024-05-15 09:36:38.678  INFO 24390 --- [[product-topic]] 
.support.classic.AssignmentAdapterHelper : Using NO-OP resume strategy
+2024-05-15 09:36:38.680  INFO 24390 --- [[product-topic]] 
.camel.component.kafka.KafkaFetchRecords : Searching for a custom subscribe 
adapter on the registry
+2024-05-15 09:36:38.681  INFO 24390 --- [[product-topic]] 
port.subcription.DefaultSubscribeAdapter : Subscribing to topic(s) product-topic
+2024-05-15 09:36:38.682  INFO 24390 --- [[product-topic]] 
che.kafka.clients.consumer.KafkaConsumer : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Subscribed to topic(s): 
product-topic
+2024-05-15 09:36:38.911  WARN 24390 --- [[product-topic]] 
org.apache.kafka.clients.NetworkClient   : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Error while fetching metadata 
with correlation id 2 : {product-topic=LEADER_NOT_AVAILABLE}
+2024-05-15 09:36:38.912  INFO 24390 --- [[product-topic]] 
org.apache.kafka.clients.Metadata        : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Cluster ID: cQJRW1YgSxubt8WdH4p2Tw
+2024-05-15 09:36:38.913  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Discovered group coordinator 
ghost.homenet.telecomitalia.it:9092 (id: 2147483647 rack: null)
+2024-05-15 09:36:38.930  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] (Re-)joining group
+2024-05-15 09:36:38.946  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Request joining group due to: 
need to re-join with the given member-id: 
consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1-b2c32bb9-ed6b-4929-988b-dcc93abf723a
+2024-05-15 09:36:38.947  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Request joining group due to: 
rebalance failed due to 'The group member needs to have a valid member id 
before actually entering a consumer group.' (MemberIdRequiredException)
+2024-05-15 09:36:38.947  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] (Re-)joining group
+2024-05-15 09:36:38.949  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Successfully joined group with 
generation Generation{generationId=1, 
memberId='consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1-b2c32bb9-ed6b-4929-988b-dcc93abf723a',
 protocol='range'}
+2024-05-15 09:36:39.040  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Finished assignment for group at 
generation 1: 
{consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1-b2c32bb9-ed6b-4929-988b-dcc93abf723a=Assignment(partitions=[product-topic-0])}
+2024-05-15 09:36:39.049  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Successfully synced group in 
generation Generation{generationId=1, 
memberId='consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1-b2c32bb9-ed6b-4929-988b-dcc93abf723a',
 protocol='range'}
+2024-05-15 09:36:39.050  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Notifying assignor about the new 
Assignment(partitions=[product-topic-0])
+2024-05-15 09:36:39.053  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Adding newly assigned partitions: 
product-topic-0
+2024-05-15 09:36:39.066  INFO 24390 --- [[product-topic]] 
s.consumer.internals.ConsumerCoordinator : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Found no committed offset for 
partition product-topic-0
+2024-05-15 09:36:39.074  INFO 24390 --- [[product-topic]] 
nts.consumer.internals.SubscriptionState : [Consumer 
clientId=consumer-016aa1d1-831c-47a9-9e26-39191e5a1d4d-1, 
groupId=016aa1d1-831c-47a9-9e26-39191e5a1d4d] Resetting offset for partition 
product-topic-0 to position FetchPosition{offset=0, offsetEpoch=Optional.empty, 
currentLeader=LeaderAndEpoch{leader=Optional[ghost.homenet.telecomitalia.it:9092
 (id: 0 rack: null)], epoch=0}}.
+
+```
+
+and after a message has been produced to Kafka you should see
+
+```bash
+2024-05-15 09:37:27.748  INFO 24390 --- [[product-topic]] log-sink             
                    : Exchange[
+  ExchangePattern: InOnly
+  Headers: {apicurio.value.globalId=, 
apicurio.value.msgType=com.acme.example.kafka.models.Product, 
CamelMessageTimestamp=1715758647152, kafka.HEADERS=RecordHeaders(headers = 
[RecordHeader(key = apicurio.value.globalId, value = [0, 0, 0, 0, 0, 0, 0, 4]), 
RecordHeader(key = apicurio.value.msgType, value = [99, 111, 109, 46, 97, 99, 
109, 101, 46, 101, 120, 97, 109, 112, 108, 101, 46, 107, 97, 102, 107, 97, 46, 
109, 111, 100, 101, 108, 115, 46, 80, 114, 111, 100, 117, 99, 116])], 
isReadOnly [...]
+  BodyType: com.acme.example.kafka.models.Product
+  Body: Product{id=1, name='product'}
+]
+```
+
+As you might see the WrongProduct record won't be in the product-topic since 
it won't pass the validation.
+
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/application.properties 
b/jbang/kafka-apicurio-secured-json-schema-registry/application.properties
new file mode 100644
index 0000000..59d24f8
--- /dev/null
+++ b/jbang/kafka-apicurio-secured-json-schema-registry/application.properties
@@ -0,0 +1,9 @@
+bootstrap.servers=localhost:9092
+topic=product-topic
+schema.registry.url=http://localhost:8081/apis/registry/v2
+keycloak.service.url=http://localhost:8080/
+keycloak.realm=registry
+keycloak.client.id=registry-api
+keycloak.client.secret=oTvqCgvcR8icj4iI1MM8ISJ2ZCE2wdwZ
+keycloak.apicurio.username=registry-account
+keycloak.apicurio.password=registry
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config-registry.yml
 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config-registry.yml
new file mode 100644
index 0000000..75c3516
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config-registry.yml
@@ -0,0 +1,56 @@
+version: '2.2'
+
+volumes:
+  postgres_data:
+    driver: local
+
+services:
+  keycloak-server:
+    container_name: keycloak-apicurio
+    image: quay.io/keycloak/keycloak:23.0.7
+    environment:
+      KEYCLOAK_ADMIN: admin
+      KEYCLOAK_ADMIN_PASSWORD: admin
+      KC_HOSTNAME: "localhost"
+      KC_HOSTNAME_PORT: "8080"
+      KC_HOSTNAME_STRICT_BACKCHANNEL: "false"
+    command:
+      - start-dev
+      - --import-realm
+    ports:
+      - 8080:8080
+    volumes:
+      - 
./config/keycloak/apicurio-realm.json:/opt/keycloak/data/import/realm.json
+
+  postgres:
+    container_name: database-apicurio
+    image: postgres
+    environment:
+      POSTGRES_USER: apicurio-registry
+      POSTGRES_PASSWORD: password
+  app:
+    image: quay.io/apicurio/apicurio-registry-sql:2.4.12.Final
+    environment:
+      REGISTRY_DATASOURCE_URL: 
'jdbc:postgresql://database-apicurio:5432/apicurio-registry'
+      REGISTRY_DATASOURCE_USERNAME: apicurio-registry
+      REGISTRY_DATASOURCE_PASSWORD: password
+      REGISTRY_STORAGE_KIND: "sql"
+      REGISTRY_STORAGE_DB_KIND: "postgresql"
+      AUTH_ENABLED: "true"
+      KEYCLOAK_REALM: registry
+      QUARKUS_HTTP_PORT: 8081
+      KEYCLOAK_URL: "http://localhost:8080";
+      LOG_LEVEL: "DEBUG"
+      REGISTRY_UI_CONFIG_AUTH_KEYCLOAK_URL: "http://localhost:8080";
+      QUARKUS_OIDC_AUTH_SERVER_URL: 
"http://keycloak-server:8080/realms/registry";
+      TOKEN_ENDPOINT: 
"http://keycloak-server:8080/realms/registry/protocol/openid-connect/token";
+      KEYCLOAK_API_CLIENT_ID: registry-api
+      REGISTRY_UI_AUTH_OIDC_CLIENTID: apicurio-registry
+      QUARKUS_OIDC_TLS_VERIFICATION: "none"
+      CORS_ALLOWED_ORIGINS: '*'
+      QUARKUS_PROFILE: "prod"
+    ports:
+      - 8081:8081
+    depends_on:
+      - postgres
+      - keycloak-server
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/keycloak/apicurio-realm.json
 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/keycloak/apicurio-realm.json
new file mode 100644
index 0000000..49e53b8
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/keycloak/apicurio-realm.json
@@ -0,0 +1,2235 @@
+{
+  "id": "registry",
+  "realm": "registry",
+  "notBefore": 1600933598,
+  "revokeRefreshToken": false,
+  "refreshTokenMaxReuse": 0,
+  "accessTokenLifespan": 300,
+  "accessTokenLifespanForImplicitFlow": 900,
+  "ssoSessionIdleTimeout": 1800,
+  "ssoSessionMaxLifespan": 36000,
+  "ssoSessionIdleTimeoutRememberMe": 0,
+  "ssoSessionMaxLifespanRememberMe": 0,
+  "offlineSessionIdleTimeout": 2592000,
+  "offlineSessionMaxLifespanEnabled": false,
+  "offlineSessionMaxLifespan": 5184000,
+  "clientSessionIdleTimeout": 0,
+  "clientSessionMaxLifespan": 0,
+  "accessCodeLifespan": 60,
+  "accessCodeLifespanUserAction": 300,
+  "accessCodeLifespanLogin": 1800,
+  "actionTokenGeneratedByAdminLifespan": 43200,
+  "actionTokenGeneratedByUserLifespan": 300,
+  "enabled": true,
+  "sslRequired": "external",
+  "registrationAllowed": true,
+  "registrationEmailAsUsername": false,
+  "rememberMe": true,
+  "verifyEmail": false,
+  "loginWithEmailAllowed": true,
+  "duplicateEmailsAllowed": false,
+  "resetPasswordAllowed": true,
+  "editUsernameAllowed": false,
+  "bruteForceProtected": false,
+  "permanentLockout": false,
+  "maxFailureWaitSeconds": 900,
+  "minimumQuickLoginWaitSeconds": 60,
+  "waitIncrementSeconds": 60,
+  "quickLoginCheckMilliSeconds": 1000,
+  "maxDeltaTimeSeconds": 43200,
+  "failureFactor": 30,
+  "roles": {
+    "realm": [
+      {
+        "id": "91363f21-2a57-4d65-954b-b3cd45d9f69c",
+        "name": "sr-admin",
+        "composite": false,
+        "clientRole": false,
+        "containerId": "registry",
+        "attributes": {}
+      },
+      {
+        "id": "b2a0eee7-c761-49a1-9426-441d467f3f98",
+        "name": "offline_access",
+        "description": "${role_offline-access}",
+        "composite": false,
+        "clientRole": false,
+        "containerId": "registry",
+        "attributes": {}
+      },
+      {
+        "id": "1ffdda65-2476-4ad5-b1e8-9f8af44a897b",
+        "name": "uma_authorization",
+        "description": "${role_uma_authorization}",
+        "composite": false,
+        "clientRole": false,
+        "containerId": "registry",
+        "attributes": {}
+      },
+      {
+        "id": "2c0937ba-7b1f-424c-927c-33cd2ccfdc62",
+        "name": "sr-developer",
+        "composite": false,
+        "clientRole": false,
+        "containerId": "registry",
+        "attributes": {}
+      },
+      {
+        "id": "a06b0184-e5bc-44c2-ae5b-4315754405f1",
+        "name": "sr-readonly",
+        "composite": false,
+        "clientRole": false,
+        "containerId": "registry",
+        "attributes": {}
+      },
+      {
+        "id": "43dd3a54-4447-4703-ad0e-cd558f78c803",
+        "name": "User",
+        "composite": false,
+        "clientRole": false,
+        "containerId": "registry",
+        "attributes": {}
+      }
+    ],
+    "client": {
+      "realm-management": [
+        {
+          "id": "dcd9e6f5-3158-4e90-ba06-e5e80e0fa05c",
+          "name": "query-users",
+          "description": "${role_query-users}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "0b4d5891-c2d9-409d-b4bd-b5daa11e059e",
+          "name": "view-identity-providers",
+          "description": "${role_view-identity-providers}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "2fee03d5-f4da-418f-843e-0a70cba351c7",
+          "name": "view-clients",
+          "description": "${role_view-clients}",
+          "composite": true,
+          "composites": {
+            "client": {
+              "realm-management": [
+                "query-clients"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "82e5542a-8ec4-4e76-aa2f-75c0eb707aad",
+          "name": "manage-realm",
+          "description": "${role_manage-realm}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "4d0d41a7-ac3f-47c6-a227-de0dc1c861de",
+          "name": "query-groups",
+          "description": "${role_query-groups}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "4d69772c-08d4-4735-954c-4115788cecbc",
+          "name": "view-events",
+          "description": "${role_view-events}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "8a79c5f9-2d14-44e4-b2bc-7e4cb955b721",
+          "name": "query-realms",
+          "description": "${role_query-realms}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "0b54c521-9672-49b5-89ab-603fe4da9693",
+          "name": "manage-events",
+          "description": "${role_manage-events}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "7a9c60b9-f2e6-4fec-ac85-7b3633a0f116",
+          "name": "realm-admin",
+          "description": "${role_realm-admin}",
+          "composite": true,
+          "composites": {
+            "client": {
+              "realm-management": [
+                "query-users",
+                "view-identity-providers",
+                "view-clients",
+                "manage-realm",
+                "query-groups",
+                "view-events",
+                "query-realms",
+                "manage-events",
+                "view-users",
+                "manage-authorization",
+                "view-authorization",
+                "manage-identity-providers",
+                "impersonation",
+                "query-clients",
+                "view-realm",
+                "manage-clients",
+                "create-client",
+                "manage-users"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "f7c5550f-8233-4347-967d-4905cbd36cec",
+          "name": "view-users",
+          "description": "${role_view-users}",
+          "composite": true,
+          "composites": {
+            "client": {
+              "realm-management": [
+                "query-users",
+                "query-groups"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "3fa4a674-d449-4576-b207-f89e556ba617",
+          "name": "manage-authorization",
+          "description": "${role_manage-authorization}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "05c8c44f-8554-4a91-b9cb-be6995144040",
+          "name": "view-authorization",
+          "description": "${role_view-authorization}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "a0c6b281-3915-45c2-9af7-d7d4f669419a",
+          "name": "manage-identity-providers",
+          "description": "${role_manage-identity-providers}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "e91f859e-d5c3-48d6-b0b0-5ff2710db3c9",
+          "name": "impersonation",
+          "description": "${role_impersonation}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "e6e6d63d-d161-444f-a58d-30875b076d16",
+          "name": "query-clients",
+          "description": "${role_query-clients}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "e50b557e-c79e-4e5a-92ee-a56b9c3925e1",
+          "name": "view-realm",
+          "description": "${role_view-realm}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "4c592e93-ba00-4661-af7d-bc50b800c060",
+          "name": "manage-clients",
+          "description": "${role_manage-clients}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "34b1cafe-ee16-42d0-9ec1-c6829e01f78c",
+          "name": "create-client",
+          "description": "${role_create-client}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        },
+        {
+          "id": "7d1d9c1e-6c1c-41eb-b8d9-6460e4d243f0",
+          "name": "manage-users",
+          "description": "${role_manage-users}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+          "attributes": {}
+        }
+      ],
+      "apicurio-registry": [],
+      "security-admin-console": [],
+      "admin-cli": [],
+      "account-console": [],
+      "broker": [
+        {
+          "id": "1ec1b34a-682d-44e7-b1fb-1d235b27b9d0",
+          "name": "read-token",
+          "description": "${role_read-token}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "717c272b-ed48-4d5a-a3cb-da5d3d3ba528",
+          "attributes": {}
+        }
+      ],
+      "account": [
+        {
+          "id": "a49e7c09-b2df-4468-96f0-65b8591774ad",
+          "name": "manage-account-links",
+          "description": "${role_manage-account-links}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "d7c9d8ec-d826-4979-970e-4d5c4d9e358b",
+          "attributes": {}
+        },
+        {
+          "id": "b6e07306-8781-4538-800b-32b2ffc5d57c",
+          "name": "view-applications",
+          "description": "${role_view-applications}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "d7c9d8ec-d826-4979-970e-4d5c4d9e358b",
+          "attributes": {}
+        },
+        {
+          "id": "6b67af9e-5c96-4944-8189-7d6c7ecc1f80",
+          "name": "view-consent",
+          "description": "${role_view-consent}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "d7c9d8ec-d826-4979-970e-4d5c4d9e358b",
+          "attributes": {}
+        },
+        {
+          "id": "aa763dea-9699-4899-95bc-f2cef6692b1d",
+          "name": "manage-consent",
+          "description": "${role_manage-consent}",
+          "composite": true,
+          "composites": {
+            "client": {
+              "account": [
+                "view-consent"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "d7c9d8ec-d826-4979-970e-4d5c4d9e358b",
+          "attributes": {}
+        },
+        {
+          "id": "aad246c6-eb26-4cfd-b840-e113021f5b9b",
+          "name": "view-profile",
+          "description": "${role_view-profile}",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "d7c9d8ec-d826-4979-970e-4d5c4d9e358b",
+          "attributes": {}
+        },
+        {
+          "id": "de065b56-c31c-41df-b110-186a798d7f17",
+          "name": "manage-account",
+          "description": "${role_manage-account}",
+          "composite": true,
+          "composites": {
+            "client": {
+              "account": [
+                "manage-account-links"
+              ]
+            }
+          },
+          "clientRole": true,
+          "containerId": "d7c9d8ec-d826-4979-970e-4d5c4d9e358b",
+          "attributes": {}
+        }
+      ],
+      "registry-api": [
+        {
+          "id": "e35b5b5f-8203-4f4c-8e9c-57cf1f0e86f5",
+          "name": "registry-user",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "69afe60b-7329-440a-9b4c-0ebec33d8902",
+          "attributes": {}
+        },
+        {
+          "id": "355ceac5-add9-4db2-a997-39ca80baf58d",
+          "name": "registry-admin",
+          "composite": false,
+          "clientRole": true,
+          "containerId": "69afe60b-7329-440a-9b4c-0ebec33d8902",
+          "attributes": {}
+        }
+      ]
+    }
+  },
+  "groups": [],
+  "defaultRoles": [
+    "offline_access",
+    "uma_authorization",
+    "User"
+  ],
+  "requiredCredentials": [
+    "password"
+  ],
+  "otpPolicyType": "totp",
+  "otpPolicyAlgorithm": "HmacSHA1",
+  "otpPolicyInitialCounter": 0,
+  "otpPolicyDigits": 6,
+  "otpPolicyLookAheadWindow": 1,
+  "otpPolicyPeriod": 30,
+  "otpSupportedApplications": [
+    "FreeOTP",
+    "Google Authenticator"
+  ],
+  "webAuthnPolicyRpEntityName": "keycloak",
+  "webAuthnPolicySignatureAlgorithms": [
+    "ES256"
+  ],
+  "webAuthnPolicyRpId": "",
+  "webAuthnPolicyAttestationConveyancePreference": "not specified",
+  "webAuthnPolicyAuthenticatorAttachment": "not specified",
+  "webAuthnPolicyRequireResidentKey": "not specified",
+  "webAuthnPolicyUserVerificationRequirement": "not specified",
+  "webAuthnPolicyCreateTimeout": 0,
+  "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
+  "webAuthnPolicyAcceptableAaguids": [],
+  "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
+  "webAuthnPolicyPasswordlessSignatureAlgorithms": [
+    "ES256"
+  ],
+  "webAuthnPolicyPasswordlessRpId": "",
+  "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
+  "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
+  "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
+  "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
+  "webAuthnPolicyPasswordlessCreateTimeout": 0,
+  "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
+  "webAuthnPolicyPasswordlessAcceptableAaguids": [],
+  "users": [
+    {
+      "id": "70dbaf4a-fcef-449c-9184-121b6cedb115",
+      "createdTimestamp": 1607594319706,
+      "username": "service-account-registry-api",
+      "enabled": true,
+      "totp": false,
+      "emailVerified": false,
+      "serviceAccountClientId": "registry-api",
+      "disableableCredentialTypes": [],
+      "requiredActions": [],
+      "realmRoles": [
+        "sr-admin",
+        "offline_access",
+        "uma_authorization",
+        "User"
+      ],
+      "clientRoles": {
+        "account": [
+          "view-applications",
+          "view-profile",
+          "manage-account"
+        ]
+      },
+      "notBefore": 0,
+      "groups": []
+    }
+  ],
+  "scopeMappings": [
+    {
+      "clientScope": "offline_access",
+      "roles": [
+        "offline_access"
+      ]
+    }
+  ],
+  "clientScopeMappings": {
+    "account": [
+      {
+        "client": "account-console",
+        "roles": [
+          "manage-account"
+        ]
+      }
+    ]
+  },
+  "clients": [
+    {
+      "id": "d7c9d8ec-d826-4979-970e-4d5c4d9e358b",
+      "clientId": "account",
+      "name": "${client_account}",
+      "rootUrl": "${authBaseUrl}",
+      "baseUrl": "/realms/registry/account/",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "defaultRoles": [
+        "view-applications",
+        "view-profile",
+        "manage-account"
+      ],
+      "redirectUris": [
+        "/realms/registry/account/*"
+      ],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    },
+    {
+      "id": "ae8d8aa5-5991-42a1-8ca8-eec12b6717f7",
+      "clientId": "account-console",
+      "name": "${client_account-console}",
+      "rootUrl": "${authBaseUrl}",
+      "baseUrl": "/realms/registry/account/",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "redirectUris": [
+        "/realms/registry/account/*"
+      ],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {
+        "pkce.code.challenge.method": "S256"
+      },
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "protocolMappers": [
+        {
+          "id": "b852b0a0-768e-4f42-badd-14cf7d2d227a",
+          "name": "audience resolve",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-audience-resolve-mapper",
+          "consentRequired": false,
+          "config": {}
+        }
+      ],
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    },
+    {
+      "id": "80b79538-8665-4188-921d-f4d0ad1f3113",
+      "clientId": "admin-cli",
+      "name": "${client_admin-cli}",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "redirectUris": [],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": false,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": true,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    },
+    {
+      "id": "1fa15256-6427-47fa-a144-b0b784e834c6",
+      "clientId": "apicurio-registry",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "redirectUris": [
+        "*"
+      ],
+      "webOrigins": [
+        "*"
+      ],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": true,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {
+        "saml.assertion.signature": "false",
+        "saml.multivalued.roles": "false",
+        "saml.force.post.binding": "false",
+        "saml.encrypt": "false",
+        "saml.server.signature": "false",
+        "saml.server.signature.keyinfo.ext": "false",
+        "exclude.session.state.from.auth.response": "false",
+        "saml_force_name_id_format": "false",
+        "saml.client.signature": "false",
+        "tls.client.certificate.bound.access.tokens": "false",
+        "saml.authnstatement": "false",
+        "display.on.consent.screen": "false",
+        "saml.onetimeuse.condition": "false"
+      },
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": true,
+      "nodeReRegistrationTimeout": -1,
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    },
+    {
+      "id": "717c272b-ed48-4d5a-a3cb-da5d3d3ba528",
+      "clientId": "broker",
+      "name": "${client_broker}",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "redirectUris": [],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    },
+    {
+      "id": "ff7205a6-6580-4cc3-9e97-7c4a39c7562e",
+      "clientId": "realm-management",
+      "name": "${client_realm-management}",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "redirectUris": [],
+      "webOrigins": [],
+      "notBefore": 0,
+      "bearerOnly": true,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {},
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    },
+    {
+      "id": "69afe60b-7329-440a-9b4c-0ebec33d8902",
+      "clientId": "registry-api",
+      "rootUrl": "http://localhost:8080";,
+      "adminUrl": "http://localhost:8080";,
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "redirectUris": [
+        "http://localhost:8080/*";
+      ],
+      "webOrigins": [
+        "http://localhost:8080";
+      ],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": true,
+      "directAccessGrantsEnabled": true,
+      "serviceAccountsEnabled": true,
+      "publicClient": false,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {
+        "saml.assertion.signature": "false",
+        "saml.force.post.binding": "false",
+        "saml.multivalued.roles": "false",
+        "saml.encrypt": "false",
+        "login_theme": "keycloak",
+        "saml.server.signature": "false",
+        "saml.server.signature.keyinfo.ext": "false",
+        "exclude.session.state.from.auth.response": "false",
+        "saml_force_name_id_format": "false",
+        "saml.client.signature": "false",
+        "tls.client.certificate.bound.access.tokens": "false",
+        "saml.authnstatement": "false",
+        "display.on.consent.screen": "false",
+        "saml.onetimeuse.condition": "false"
+      },
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": true,
+      "nodeReRegistrationTimeout": -1,
+      "protocolMappers": [
+        {
+          "id": "83a4a269-207b-4818-bbbb-a04abebb2997",
+          "name": "Client IP Address",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usersessionmodel-note-mapper",
+          "consentRequired": false,
+          "config": {
+            "user.session.note": "clientAddress",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "clientAddress",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "20241caf-ebb6-467f-acae-7543b143c289",
+          "name": "Client ID",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usersessionmodel-note-mapper",
+          "consentRequired": false,
+          "config": {
+            "user.session.note": "clientId",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "clientId",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "eb3a14a2-5c4c-4dd7-99dc-e2734c8c5d98",
+          "name": "Client Host",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usersessionmodel-note-mapper",
+          "consentRequired": false,
+          "config": {
+            "user.session.note": "clientHost",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "clientHost",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    },
+    {
+      "id": "f1beca1a-0756-4dc6-9719-9234cd9b779f",
+      "clientId": "security-admin-console",
+      "name": "${client_security-admin-console}",
+      "rootUrl": "${authAdminUrl}",
+      "baseUrl": "/admin/registry/console/",
+      "surrogateAuthRequired": false,
+      "enabled": true,
+      "alwaysDisplayInConsole": false,
+      "clientAuthenticatorType": "client-secret",
+      "secret": "**********",
+      "redirectUris": [
+        "/admin/registry/console/*"
+      ],
+      "webOrigins": [
+        "+"
+      ],
+      "notBefore": 0,
+      "bearerOnly": false,
+      "consentRequired": false,
+      "standardFlowEnabled": true,
+      "implicitFlowEnabled": false,
+      "directAccessGrantsEnabled": false,
+      "serviceAccountsEnabled": false,
+      "publicClient": true,
+      "frontchannelLogout": false,
+      "protocol": "openid-connect",
+      "attributes": {
+        "pkce.code.challenge.method": "S256"
+      },
+      "authenticationFlowBindingOverrides": {},
+      "fullScopeAllowed": false,
+      "nodeReRegistrationTimeout": 0,
+      "protocolMappers": [
+        {
+          "id": "cb9b9e1a-63a0-460e-a42f-14d1ace49da3",
+          "name": "locale",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "locale",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "locale",
+            "jsonType.label": "String"
+          }
+        }
+      ],
+      "defaultClientScopes": [
+        "web-origins",
+        "role_list",
+        "profile",
+        "roles",
+        "email"
+      ],
+      "optionalClientScopes": [
+        "address",
+        "phone",
+        "offline_access",
+        "microprofile-jwt"
+      ]
+    }
+  ],
+  "clientScopes": [
+    {
+      "id": "65eabc09-c5a1-4a0e-830c-44a430c129f0",
+      "name": "offline_access",
+      "description": "OpenID Connect built-in scope: offline_access",
+      "protocol": "openid-connect",
+      "attributes": {
+        "consent.screen.text": "${offlineAccessScopeConsentText}",
+        "display.on.consent.screen": "true"
+      }
+    },
+    {
+      "id": "5074f873-23f3-4d03-9b75-6c6af91fb7ed",
+      "name": "role_list",
+      "description": "SAML role list",
+      "protocol": "saml",
+      "attributes": {
+        "consent.screen.text": "${samlRoleListScopeConsentText}",
+        "display.on.consent.screen": "true"
+      },
+      "protocolMappers": [
+        {
+          "id": "ab3d0106-d086-4813-930b-5a27ddfe038b",
+          "name": "role list",
+          "protocol": "saml",
+          "protocolMapper": "saml-role-list-mapper",
+          "consentRequired": false,
+          "config": {
+            "single": "false",
+            "attribute.nameformat": "Basic",
+            "attribute.name": "Role"
+          }
+        }
+      ]
+    },
+    {
+      "id": "9f0f742e-6202-4543-80e3-80fb2fbfc042",
+      "name": "profile",
+      "description": "OpenID Connect built-in scope: profile",
+      "protocol": "openid-connect",
+      "attributes": {
+        "include.in.token.scope": "true",
+        "display.on.consent.screen": "true",
+        "consent.screen.text": "${profileScopeConsentText}"
+      },
+      "protocolMappers": [
+        {
+          "id": "033dab17-488c-400d-b603-f75ebe1949b7",
+          "name": "family name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "lastName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "family_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "c87aca2f-23dd-4fc7-b79f-a9b061c165e4",
+          "name": "nickname",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "nickname",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "nickname",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "4361eae6-7021-49e1-a387-3d8bc4f50247",
+          "name": "birthdate",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "birthdate",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "birthdate",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "35c03d95-ce9d-4fd2-823b-23e896dbb105",
+          "name": "gender",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "gender",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "gender",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "0ff4cd3c-6567-4935-bbe8-0191a9bcdd72",
+          "name": "locale",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "locale",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "locale",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "8e087dfd-2978-4ea5-9ed2-32efca9a98c5",
+          "name": "given name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "firstName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "given_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "31a3c477-3aab-46cd-81e3-2b76b2c8c21c",
+          "name": "profile",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "profile",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "profile",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "a3606512-379b-4bcb-999d-29cf17812012",
+          "name": "website",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "website",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "website",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "2f535da7-ea99-4f8d-acbe-988a3691034b",
+          "name": "username",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "preferred_username",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "2fbfe26c-b175-4b16-97ea-edea4072181a",
+          "name": "picture",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "picture",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "picture",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "17e5a7d4-2e77-4ff4-8c71-b93e41e4e1bb",
+          "name": "full name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-full-name-mapper",
+          "consentRequired": false,
+          "config": {
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "userinfo.token.claim": "true"
+          }
+        },
+        {
+          "id": "ca64060a-1d26-43ca-aae7-23c62ed805d4",
+          "name": "zoneinfo",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "zoneinfo",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "zoneinfo",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "beaddf45-8040-42cd-9236-55fe2134f5df",
+          "name": "middle name",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "middleName",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "middle_name",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "043c162e-e0ba-418b-b965-157f6a52db46",
+          "name": "updated at",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "updatedAt",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "updated_at",
+            "jsonType.label": "String"
+          }
+        }
+      ]
+    },
+    {
+      "id": "a2766301-ac7f-42f4-bfbe-87d2fdcef382",
+      "name": "email",
+      "description": "OpenID Connect built-in scope: email",
+      "protocol": "openid-connect",
+      "attributes": {
+        "include.in.token.scope": "true",
+        "display.on.consent.screen": "true",
+        "consent.screen.text": "${emailScopeConsentText}"
+      },
+      "protocolMappers": [
+        {
+          "id": "35bbe3f0-d5a3-4785-b3dc-d187330b699d",
+          "name": "email",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "email",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "d439a3d1-c6da-4138-87df-c1b851e7b9c8",
+          "name": "email verified",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "emailVerified",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "email_verified",
+            "jsonType.label": "boolean"
+          }
+        }
+      ]
+    },
+    {
+      "id": "5539a2b5-6e75-4533-aaaa-800101d0df4d",
+      "name": "address",
+      "description": "OpenID Connect built-in scope: address",
+      "protocol": "openid-connect",
+      "attributes": {
+        "include.in.token.scope": "true",
+        "display.on.consent.screen": "true",
+        "consent.screen.text": "${addressScopeConsentText}"
+      },
+      "protocolMappers": [
+        {
+          "id": "f7c31e38-1dda-4dcc-82b6-c7d958416962",
+          "name": "address",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-address-mapper",
+          "consentRequired": false,
+          "config": {
+            "user.attribute.formatted": "formatted",
+            "user.attribute.country": "country",
+            "user.attribute.postal_code": "postal_code",
+            "userinfo.token.claim": "true",
+            "user.attribute.street": "street",
+            "id.token.claim": "true",
+            "user.attribute.region": "region",
+            "access.token.claim": "true",
+            "user.attribute.locality": "locality"
+          }
+        }
+      ]
+    },
+    {
+      "id": "90c61a9b-39ac-4dbd-af49-9123739f98f9",
+      "name": "phone",
+      "description": "OpenID Connect built-in scope: phone",
+      "protocol": "openid-connect",
+      "attributes": {
+        "include.in.token.scope": "true",
+        "display.on.consent.screen": "true",
+        "consent.screen.text": "${phoneScopeConsentText}"
+      },
+      "protocolMappers": [
+        {
+          "id": "9170cc7f-5624-4a15-b50d-cd1b9a0ffb6f",
+          "name": "phone number verified",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "phoneNumberVerified",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "phone_number_verified",
+            "jsonType.label": "boolean"
+          }
+        },
+        {
+          "id": "f2d44f21-de2f-47d8-b0d5-4e46f9de581b",
+          "name": "phone number",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-attribute-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "phoneNumber",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "phone_number",
+            "jsonType.label": "String"
+          }
+        }
+      ]
+    },
+    {
+      "id": "db64f4f6-e562-4e43-9f17-255b8a21c5ca",
+      "name": "roles",
+      "description": "OpenID Connect scope for add user roles to the access 
token",
+      "protocol": "openid-connect",
+      "attributes": {
+        "include.in.token.scope": "false",
+        "display.on.consent.screen": "true",
+        "consent.screen.text": "${rolesScopeConsentText}"
+      },
+      "protocolMappers": [
+        {
+          "id": "bfdfc98c-59eb-4a05-9a74-dd1bb4dea691",
+          "name": "client roles",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-client-role-mapper",
+          "consentRequired": false,
+          "config": {
+            "user.attribute": "foo",
+            "access.token.claim": "true",
+            "claim.name": "resource_access.${client_id}.roles",
+            "jsonType.label": "String",
+            "multivalued": "true"
+          }
+        },
+        {
+          "id": "e285b5a4-2854-46d8-bd06-6ca2911dde8a",
+          "name": "realm roles",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-realm-role-mapper",
+          "consentRequired": false,
+          "config": {
+            "user.attribute": "foo",
+            "access.token.claim": "true",
+            "claim.name": "realm_access.roles",
+            "jsonType.label": "String",
+            "multivalued": "true"
+          }
+        },
+        {
+          "id": "c6da4bb5-fc32-4e34-88ac-72ca671afd3f",
+          "name": "audience resolve",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-audience-resolve-mapper",
+          "consentRequired": false,
+          "config": {}
+        }
+      ]
+    },
+    {
+      "id": "ab66a766-4d9d-40ac-bcc9-264cd5471b92",
+      "name": "web-origins",
+      "description": "OpenID Connect scope for add allowed web origins to the 
access token",
+      "protocol": "openid-connect",
+      "attributes": {
+        "include.in.token.scope": "false",
+        "display.on.consent.screen": "false",
+        "consent.screen.text": ""
+      },
+      "protocolMappers": [
+        {
+          "id": "1b1867ba-1a17-412d-ab97-0ae88963d5b5",
+          "name": "allowed web origins",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-allowed-origins-mapper",
+          "consentRequired": false,
+          "config": {}
+        }
+      ]
+    },
+    {
+      "id": "d6f896d6-b31b-487e-b4a8-af921d3d04eb",
+      "name": "microprofile-jwt",
+      "description": "Microprofile - JWT built-in scope",
+      "protocol": "openid-connect",
+      "attributes": {
+        "include.in.token.scope": "true",
+        "display.on.consent.screen": "false"
+      },
+      "protocolMappers": [
+        {
+          "id": "c7831e59-070e-4d77-8382-d5ef4f60ddd4",
+          "name": "upn",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-property-mapper",
+          "consentRequired": false,
+          "config": {
+            "userinfo.token.claim": "true",
+            "user.attribute": "username",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "upn",
+            "jsonType.label": "String"
+          }
+        },
+        {
+          "id": "3456b5e1-4852-48ac-8420-79568ffd9a89",
+          "name": "groups",
+          "protocol": "openid-connect",
+          "protocolMapper": "oidc-usermodel-realm-role-mapper",
+          "consentRequired": false,
+          "config": {
+            "multivalued": "true",
+            "userinfo.token.claim": "true",
+            "user.attribute": "foo",
+            "id.token.claim": "true",
+            "access.token.claim": "true",
+            "claim.name": "groups",
+            "jsonType.label": "String"
+          }
+        }
+      ]
+    }
+  ],
+  "defaultDefaultClientScopes": [
+    "role_list",
+    "profile",
+    "email",
+    "roles",
+    "web-origins"
+  ],
+  "defaultOptionalClientScopes": [
+    "offline_access",
+    "address",
+    "phone",
+    "microprofile-jwt"
+  ],
+  "browserSecurityHeaders": {
+    "contentSecurityPolicyReportOnly": "",
+    "xContentTypeOptions": "nosniff",
+    "xRobotsTag": "none",
+    "xFrameOptions": "SAMEORIGIN",
+    "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; 
object-src 'none';",
+    "xXSSProtection": "1; mode=block",
+    "strictTransportSecurity": "max-age=31536000; includeSubDomains"
+  },
+  "smtpServer": {},
+  "loginTheme": "keycloak",
+  "accountTheme": "keycloak",
+  "adminTheme": "keycloak",
+  "emailTheme": "keycloak",
+  "eventsEnabled": false,
+  "eventsListeners": [
+    "jboss-logging"
+  ],
+  "enabledEventTypes": [],
+  "adminEventsEnabled": false,
+  "adminEventsDetailsEnabled": false,
+  "components": {
+    
"org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
+      {
+        "id": "6b7d0997-665b-4567-b955-f41029b1f7c6",
+        "name": "Allowed Client Scopes",
+        "providerId": "allowed-client-templates",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {
+          "allow-default-scopes": [
+            "true"
+          ]
+        }
+      },
+      {
+        "id": "b2062994-7819-4b5b-bcaf-bd565e0261f7",
+        "name": "Trusted Hosts",
+        "providerId": "trusted-hosts",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {
+          "host-sending-registration-request-must-match": [
+            "true"
+          ],
+          "client-uris-must-match": [
+            "true"
+          ]
+        }
+      },
+      {
+        "id": "e28102af-287e-40d3-a64d-636f9d0af6c0",
+        "name": "Consent Required",
+        "providerId": "consent-required",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {}
+      },
+      {
+        "id": "7ea991c6-db4b-4989-87c1-2cf0b2e2b371",
+        "name": "Allowed Client Scopes",
+        "providerId": "allowed-client-templates",
+        "subType": "authenticated",
+        "subComponents": {},
+        "config": {
+          "allow-default-scopes": [
+            "true"
+          ]
+        }
+      },
+      {
+        "id": "c2aa0c17-6405-441a-96d8-7174001b1f6e",
+        "name": "Allowed Protocol Mapper Types",
+        "providerId": "allowed-protocol-mappers",
+        "subType": "authenticated",
+        "subComponents": {},
+        "config": {
+          "allowed-protocol-mapper-types": [
+            "oidc-usermodel-property-mapper",
+            "oidc-address-mapper",
+            "oidc-full-name-mapper",
+            "saml-user-attribute-mapper",
+            "saml-user-property-mapper",
+            "oidc-sha256-pairwise-sub-mapper",
+            "oidc-usermodel-attribute-mapper",
+            "saml-role-list-mapper"
+          ]
+        }
+      },
+      {
+        "id": "f1d9cee9-fa10-451a-a96f-486c1abc9184",
+        "name": "Full Scope Disabled",
+        "providerId": "scope",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {}
+      },
+      {
+        "id": "398d86a9-4247-4923-b3bf-a94ef18974f2",
+        "name": "Max Clients Limit",
+        "providerId": "max-clients",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {
+          "max-clients": [
+            "200"
+          ]
+        }
+      },
+      {
+        "id": "fd8139d0-82ee-453e-a9aa-0bbd10538eff",
+        "name": "Allowed Protocol Mapper Types",
+        "providerId": "allowed-protocol-mappers",
+        "subType": "anonymous",
+        "subComponents": {},
+        "config": {
+          "allowed-protocol-mapper-types": [
+            "oidc-sha256-pairwise-sub-mapper",
+            "oidc-usermodel-property-mapper",
+            "oidc-address-mapper",
+            "saml-role-list-mapper",
+            "oidc-usermodel-attribute-mapper",
+            "oidc-full-name-mapper",
+            "saml-user-property-mapper",
+            "saml-user-attribute-mapper"
+          ]
+        }
+      }
+    ],
+    "org.keycloak.keys.KeyProvider": [
+      {
+        "id": "9ec415cf-5494-4823-a83d-cc38441b088c",
+        "name": "aes-generated",
+        "providerId": "aes-generated",
+        "subComponents": {},
+        "config": {
+          "priority": [
+            "100"
+          ]
+        }
+      },
+      {
+        "id": "cd2dc9b1-a252-4f70-93c0-5bdb51532236",
+        "name": "hmac-generated",
+        "providerId": "hmac-generated",
+        "subComponents": {},
+        "config": {
+          "priority": [
+            "100"
+          ],
+          "algorithm": [
+            "HS256"
+          ]
+        }
+      },
+      {
+        "id": "2dc91aa5-3084-4ceb-973e-24d78e78777a",
+        "name": "rsa-generated",
+        "providerId": "rsa-generated",
+        "subComponents": {},
+        "config": {
+          "priority": [
+            "100"
+          ]
+        }
+      }
+    ]
+  },
+  "internationalizationEnabled": false,
+  "supportedLocales": [
+    ""
+  ],
+  "authenticationFlows": [
+    {
+      "id": "6ceb1698-b456-497c-a959-92628d484a5e",
+      "alias": "Account verification options",
+      "description": "Method with which to verity the existing account",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "idp-email-verification",
+          "requirement": "ALTERNATIVE",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "ALTERNATIVE",
+          "priority": 20,
+          "flowAlias": "Verify Existing Account by Re-authentication",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "e947aa99-a5db-4136-b1a7-5a942f09a5bc",
+      "alias": "Authentication Options",
+      "description": "Authentication options.",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "basic-auth",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "basic-auth-otp",
+          "requirement": "DISABLED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "auth-spnego",
+          "requirement": "DISABLED",
+          "priority": 30,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "eb8570fc-bd79-4905-a200-e71478fbe85f",
+      "alias": "Browser - Conditional OTP",
+      "description": "Flow to determine if the OTP is required for the 
authentication",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "conditional-user-configured",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "auth-otp-form",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "fce7d35a-9d56-4dec-b2e5-b8cfcf926430",
+      "alias": "Direct Grant - Conditional OTP",
+      "description": "Flow to determine if the OTP is required for the 
authentication",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "conditional-user-configured",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "direct-grant-validate-otp",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "f16a6dbe-599f-4567-8029-30efe34efd2e",
+      "alias": "First broker login - Conditional OTP",
+      "description": "Flow to determine if the OTP is required for the 
authentication",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "conditional-user-configured",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "auth-otp-form",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "77a7b8f1-7a78-45f9-8ba4-5c82fc3dc7dc",
+      "alias": "Handle Existing Account",
+      "description": "Handle what to do if there is existing account with same 
email/username like authenticated identity provider",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "idp-confirm-link",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "flowAlias": "Account verification options",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "7b1e82e3-efe0-4429-8412-a69aeef275ed",
+      "alias": "Reset - Conditional OTP",
+      "description": "Flow to determine if the OTP should be reset or not. Set 
to REQUIRED to force.",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "conditional-user-configured",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "reset-otp",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "388cb33f-49b7-47e0-9762-02bf5c2443bc",
+      "alias": "User creation or linking",
+      "description": "Flow for the existing/non-existing user alternatives",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticatorConfig": "create unique user config",
+          "authenticator": "idp-create-user-if-unique",
+          "requirement": "ALTERNATIVE",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "ALTERNATIVE",
+          "priority": 20,
+          "flowAlias": "Handle Existing Account",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "ef0c0995-4853-4acf-8f13-15f9861aa0ee",
+      "alias": "Verify Existing Account by Re-authentication",
+      "description": "Reauthentication of existing account",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "idp-username-password-form",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "CONDITIONAL",
+          "priority": 20,
+          "flowAlias": "First broker login - Conditional OTP",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "98e6806a-7a04-471f-9a16-70e028388f70",
+      "alias": "browser",
+      "description": "browser based authentication",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "auth-cookie",
+          "requirement": "ALTERNATIVE",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "auth-spnego",
+          "requirement": "DISABLED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "identity-provider-redirector",
+          "requirement": "ALTERNATIVE",
+          "priority": 25,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "ALTERNATIVE",
+          "priority": 30,
+          "flowAlias": "forms",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "cdf65f9e-d1b6-49c3-9b0a-3ae912c71339",
+      "alias": "clients",
+      "description": "Base authentication for clients",
+      "providerId": "client-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "client-secret",
+          "requirement": "ALTERNATIVE",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "client-jwt",
+          "requirement": "ALTERNATIVE",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "client-secret-jwt",
+          "requirement": "ALTERNATIVE",
+          "priority": 30,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "client-x509",
+          "requirement": "ALTERNATIVE",
+          "priority": 40,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "3934d6db-1b75-484b-a1ec-bb1d9e4f4a27",
+      "alias": "direct grant",
+      "description": "OpenID Connect Resource Owner Grant",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "direct-grant-validate-username",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "direct-grant-validate-password",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "CONDITIONAL",
+          "priority": 30,
+          "flowAlias": "Direct Grant - Conditional OTP",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "d2f67169-3047-4d9e-981e-f040f47e3bad",
+      "alias": "docker auth",
+      "description": "Used by Docker clients to authenticate against the IDP",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "docker-http-basic-authenticator",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "f87acaf9-0947-4499-9d76-4da8052ae92c",
+      "alias": "first broker login",
+      "description": "Actions taken after first broker login with identity 
provider account, which is not yet linked to any Keycloak account",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticatorConfig": "review profile config",
+          "authenticator": "idp-review-profile",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "flowAlias": "User creation or linking",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "830bbe5e-335c-44a4-8ebb-2f002995ea60",
+      "alias": "forms",
+      "description": "Username, password, otp and other auth forms.",
+      "providerId": "basic-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "auth-username-password-form",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "CONDITIONAL",
+          "priority": 20,
+          "flowAlias": "Browser - Conditional OTP",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "34878920-2746-4a25-bedf-6b1d27348841",
+      "alias": "http challenge",
+      "description": "An authentication flow based on challenge-response HTTP 
Authentication Schemes",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "no-cookie-redirect",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "flowAlias": "Authentication Options",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "19f5cfd2-209c-44b7-aee3-945bcc92f387",
+      "alias": "registration",
+      "description": "registration flow",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "registration-page-form",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "flowAlias": "registration form",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "a08016e3-8d79-4772-ab1c-5aeb77366aa7",
+      "alias": "registration form",
+      "description": "registration form",
+      "providerId": "form-flow",
+      "topLevel": false,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "registration-user-creation",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "registration-profile-action",
+          "requirement": "REQUIRED",
+          "priority": 40,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "registration-password-action",
+          "requirement": "REQUIRED",
+          "priority": 50,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "registration-recaptcha-action",
+          "requirement": "DISABLED",
+          "priority": 60,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    },
+    {
+      "id": "050a5e25-26c2-4b2b-aa47-176eb21a0011",
+      "alias": "reset credentials",
+      "description": "Reset credentials for a user if they forgot their 
password or something",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "reset-credentials-choose-user",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "reset-credential-email",
+          "requirement": "REQUIRED",
+          "priority": 20,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "authenticator": "reset-password",
+          "requirement": "REQUIRED",
+          "priority": 30,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        },
+        {
+          "requirement": "CONDITIONAL",
+          "priority": 40,
+          "flowAlias": "Reset - Conditional OTP",
+          "userSetupAllowed": false,
+          "autheticatorFlow": true
+        }
+      ]
+    },
+    {
+      "id": "27464d2b-c1c8-4ded-83dd-03332a427e6e",
+      "alias": "saml ecp",
+      "description": "SAML ECP Profile Authentication Flow",
+      "providerId": "basic-flow",
+      "topLevel": true,
+      "builtIn": true,
+      "authenticationExecutions": [
+        {
+          "authenticator": "http-basic-authenticator",
+          "requirement": "REQUIRED",
+          "priority": 10,
+          "userSetupAllowed": false,
+          "autheticatorFlow": false
+        }
+      ]
+    }
+  ],
+  "authenticatorConfig": [
+    {
+      "id": "cb3b3118-fba0-4d35-a04d-84385f82d1f7",
+      "alias": "create unique user config",
+      "config": {
+        "require.password.update.after.registration": "false"
+      }
+    },
+    {
+      "id": "ba525d9d-19af-4d8e-9c2a-2a906d627690",
+      "alias": "review profile config",
+      "config": {
+        "update.profile.on.first.login": "missing"
+      }
+    }
+  ],
+  "requiredActions": [
+    {
+      "alias": "CONFIGURE_TOTP",
+      "name": "Configure OTP",
+      "providerId": "CONFIGURE_TOTP",
+      "enabled": true,
+      "defaultAction": false,
+      "priority": 10,
+      "config": {}
+    },
+    {
+      "alias": "terms_and_conditions",
+      "name": "Terms and Conditions",
+      "providerId": "terms_and_conditions",
+      "enabled": false,
+      "defaultAction": false,
+      "priority": 20,
+      "config": {}
+    },
+    {
+      "alias": "UPDATE_PASSWORD",
+      "name": "Update Password",
+      "providerId": "UPDATE_PASSWORD",
+      "enabled": true,
+      "defaultAction": false,
+      "priority": 30,
+      "config": {}
+    },
+    {
+      "alias": "UPDATE_PROFILE",
+      "name": "Update Profile",
+      "providerId": "UPDATE_PROFILE",
+      "enabled": true,
+      "defaultAction": false,
+      "priority": 40,
+      "config": {}
+    },
+    {
+      "alias": "VERIFY_EMAIL",
+      "name": "Verify Email",
+      "providerId": "VERIFY_EMAIL",
+      "enabled": true,
+      "defaultAction": false,
+      "priority": 50,
+      "config": {}
+    },
+    {
+      "alias": "update_user_locale",
+      "name": "Update User Locale",
+      "providerId": "update_user_locale",
+      "enabled": true,
+      "defaultAction": false,
+      "priority": 1000,
+      "config": {}
+    }
+  ],
+  "browserFlow": "browser",
+  "registrationFlow": "registration",
+  "directGrantFlow": "direct grant",
+  "resetCredentialsFlow": "reset credentials",
+  "clientAuthenticationFlow": "clients",
+  "dockerAuthenticationFlow": "docker auth",
+  "attributes": {
+    "clientSessionIdleTimeout": "0",
+    "clientSessionMaxLifespan": "0"
+  },
+  "keycloakVersion": "10.0.2",
+  "userManagedAccessAllowed": true
+}
\ No newline at end of file
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/prometheus.yml
 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/prometheus.yml
new file mode 100644
index 0000000..d7d0217
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/prometheus.yml
@@ -0,0 +1,6 @@
+scrape_configs:
+  - job_name: apicurio-registry
+    scrape_interval: 3s
+    static_configs:
+      - targets:
+          - 'app:8080'
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/provisioning/datasources/datasource.yml
 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/provisioning/datasources/datasource.yml
new file mode 100644
index 0000000..33d8631
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/docker-compose/config/provisioning/datasources/datasource.yml
@@ -0,0 +1,12 @@
+apiVersion: 1
+
+datasources:
+  name: Prometheus
+  type: prometheus
+  access: proxy
+  orgId: 1
+  url: http://prometheus:9090
+  basicAuth: false
+  isDefault: true
+  version: 1
+  editable: true
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/kafka-apicurio-kamelet.camel.yaml
 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-apicurio-kamelet.camel.yaml
new file mode 100644
index 0000000..cd8eec1
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-apicurio-kamelet.camel.yaml
@@ -0,0 +1,41 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+# camel-k: dependency=mvn:com.acme.example:kafka-apicurio-producer:0.1
+
+- route:
+    id: "kafka-to-apicurio-log"
+    from:
+      uri: "kamelet:kafka-not-secured-apicurio-registry-json-source"
+      parameters:
+        topic: "{{topic}}"
+        bootstrapServers: "{{bootstrap.servers}}"
+        groupId: 'my-consumer-group'
+        apicurioRegistryUrl: '{{schema.registry.url}}'
+        apicurioAuthServiceUrl: '{{keycloak.service.url}}'
+        apicurioAuthRealm: '{{keycloak.realm}}'
+        apicurioAuthClientId: '{{keycloak.client.id}}'
+        apicurioAuthClientSecret: '{{keycloak.client.secret}}'
+        apicurioAuthUsername: '{{keycloak.apicurio.username}}'
+        apicurioAuthPassword: '{{keycloak.apicurio.password}}'
+      steps:
+        - to:
+            uri: "kamelet:log-sink"
+            parameters:
+              showStreams: true
+              showHeaders: true
+              multiline: true
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/kafka-not-secured-apicurio-registry-json-source.kamelet.yaml
 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-not-secured-apicurio-registry-json-source.kamelet.yaml
new file mode 100644
index 0000000..588124d
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-not-secured-apicurio-registry-json-source.kamelet.yaml
@@ -0,0 +1,188 @@
+# ---------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ---------------------------------------------------------------------------
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+  name: kafka-not-secured-apicurio-registry-json-source
+  annotations:
+    camel.apache.org/kamelet.support.level: "Preview"
+    camel.apache.org/catalog.version: "4.7.0-SNAPSHOT"
+    camel.apache.org/kamelet.icon: 
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4wLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCA1MDAgNTAwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MD
 [...]
+    camel.apache.org/provider: "Apache Software Foundation"
+    camel.apache.org/kamelet.group: "Kafka"
+    camel.apache.org/kamelet.namespace: "Kafka"
+    camel.apache.org/keda.type: "kafka"
+  labels:
+    camel.apache.org/kamelet.type: "source"
+spec:
+  definition:
+    title: "Kafka not secured with Apicurio Registry secured with Keycloak 
Source"
+    description: |-
+      Receive data from Kafka topics on an insecure broker combined with 
Apicurio Registry secured with Keycloak.
+    required:
+      - topic
+      - bootstrapServers
+      - apicurioRegistryUrl
+      - apicurioAuthServiceUrl
+      - apicurioAuthRealm
+      - apicurioAuthClientId
+      - apicurioAuthClientSecret
+      - apicurioAuthUsername
+      - apicurioAuthPassword
+    type: object
+    properties:
+      topic:
+        title: Topic Names
+        description: Comma separated list of Kafka topic names
+        type: string
+        x-descriptors:
+        - urn:keda:metadata:topic
+        - urn:keda:required
+      bootstrapServers:
+        title: Bootstrap Servers
+        description: Comma separated list of Kafka Broker URLs
+        type: string
+        x-descriptors:
+        - urn:keda:metadata:bootstrapServers
+        - urn:keda:required
+      autoCommitEnable:
+        title: Auto Commit Enable
+        description: If true, periodically commit to ZooKeeper the offset of 
messages already fetched by the consumer
+        type: boolean
+        default: true
+      allowManualCommit:
+        title: Allow Manual Commit
+        description: Whether to allow doing manual commits
+        type: boolean
+        default: false
+      pollOnError:
+        title: Poll On Error Behavior
+        description: What to do if kafka threw an exception while polling for 
new messages. There are 5 enums and the value can be one of DISCARD, 
ERROR_HANDLER, RECONNECT, RETRY, STOP
+        type: string
+        default: "ERROR_HANDLER"
+      autoOffsetReset:
+        title: Auto Offset Reset
+        description: What to do when there is no initial offset. There are 3 
enums and the value can be one of latest, earliest, none
+        type: string
+        default: "latest"
+        x-descriptors:
+        - urn:keda:metadata:offsetResetPolicy
+      consumerGroup:
+        title: Consumer Group
+        description: A string that uniquely identifies the group of consumers 
to which this source belongs
+        type: string
+        example: "my-group-id"
+        x-descriptors:
+        - urn:keda:metadata:consumerGroup
+        - urn:keda:required
+      deserializeHeaders:
+        title: Automatically Deserialize Headers
+        description: When enabled the Kamelet source will deserialize all 
message headers to String representation.
+        type: boolean
+        default: true
+      valueDeserializer:
+        title: Value Deserializer
+        description: Deserializer class for value that implements the 
Deserializer interface.
+        type: string
+        default: 
"io.apicurio.registry.serde.jsonschema.JsonSchemaKafkaDeserializer"
+      apicurioRegistryUrl:
+        title: Apicurio Registry URL
+        description: The Apicurio Schema Registry URL
+        type: string
+        x-descriptors:
+        - urn:keda:metadata:bootstrapServers
+        - urn:keda:required
+      avroDatumProvider:
+        title: Avro Datum Provider
+        description: How to read data with Avro
+        type: string
+        default: "io.apicurio.registry.serde.avro.ReflectAvroDatumProvider"
+      apicurioAuthServiceUrl:
+        title: Apicurio Registry Auth Service URL
+        description: The URL for Keycloak instance securing the Apicurio 
Registry
+        type: string
+        example: "http://my-keycloak.com:8080/";
+      apicurioAuthRealm:
+        title: Apicurio Registry Auth Realm
+        description: The Realm in Keycloak instance securing the Apicurio 
Registry
+        type: string
+      apicurioAuthClientId:
+        title: Apicurio Registry Auth Client ID
+        description: The Client ID in Keycloak instance securing the Apicurio 
Registry
+        type: string
+      apicurioAuthClientSecret:
+        title: Apicurio Registry Auth Client Secret
+        description: The Client Secret in Keycloak instance securing the 
Apicurio Registry
+        type: string
+        format: password
+        x-descriptors:
+        - urn:camel:group:credentials
+        - urn:keda:authentication:password
+        - urn:keda:required
+      apicurioAuthUsername:
+        title: Apicurio Registry Auth Username
+        description: The Username in Keycloak instance securing the Apicurio 
Registry
+        type: string
+      apicurioAuthPassword:
+        title: Apicurio Registry Auth Password
+        description: The Password in Keycloak instance securing the Apicurio 
Registry
+        type: string
+        format: password
+        x-descriptors:
+        - urn:camel:group:credentials
+        - urn:keda:authentication:password
+        - urn:keda:required
+      topicIsPattern:
+        title: Topic Is Pattern
+        description: Whether the topic is a pattern (regular expression). This 
can be used to subscribe to dynamic number of topics matching the pattern.
+        type: boolean
+        default: false
+  dependencies:
+    - "mvn:org.apache.camel.kamelets:camel-kamelets-utils:4.7.0-SNAPSHOT"
+    - "camel:kafka"
+    - "camel:core"
+    - "camel:kamelet"
+    - "mvn:io.apicurio:apicurio-registry-serdes-jsonschema-serde:2.5.11.Final"
+  template:
+    beans:
+      - name: kafkaHeaderDeserializer
+        type: 
"#class:org.apache.camel.kamelets.utils.serialization.kafka.KafkaHeaderDeserializer"
+        properties:
+          enabled: '{{deserializeHeaders}}'
+    from:
+      uri: "kafka:{{topic}}"
+      parameters:
+        brokers: "{{bootstrapServers}}"
+        autoCommitEnable: "{{autoCommitEnable}}"
+        allowManualCommit: "{{allowManualCommit}}"
+        pollOnError: "{{pollOnError}}"
+        autoOffsetReset: "{{autoOffsetReset}}"
+        groupId: "{{?consumerGroup}}"
+        valueDeserializer: "{{valueDeserializer}}"
+        topicIsPattern: "{{topicIsPattern}}"
+        additionalProperties.apicurio.registry.url: "{{apicurioRegistryUrl}}"
+        additionalProperties.apicurio.registry.avro-datum-provider: 
"{{avroDatumProvider}}"
+        additionalProperties.apicurio.auth.service.url: 
"{{apicurioAuthServiceUrl}}"
+        additionalProperties.apicurio.auth.realm: "{{apicurioAuthRealm}}"
+        additionalProperties.apicurio.auth.client.id: 
"{{apicurioAuthClientId}}"
+        additionalProperties.apicurio.auth.client.secret: 
"{{apicurioAuthClientSecret}}"
+        additionalProperties.apicurio.auth.username: "{{apicurioAuthUsername}}"
+        additionalProperties.apicurio.auth.password: "{{apicurioAuthPassword}}"
+      steps:
+        - process:
+            ref: "{{kafkaHeaderDeserializer}}"
+        - to: "kamelet:sink"
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/pom.xml 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/pom.xml
new file mode 100644
index 0000000..e7e8c3f
--- /dev/null
+++ b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/pom.xml
@@ -0,0 +1,60 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>com.acme.example</groupId>
+  <artifactId>kafka-apicurio-producer</artifactId>
+  <packaging>jar</packaging>
+  <version>0.1</version>
+  <name>kafka-apicurio-prod</name>
+  <url>http://maven.apache.org</url>
+  <dependencies>
+
+    <dependency>
+      <groupId>io.apicurio</groupId>
+      <artifactId>apicurio-registry-serdes-jsonschema-serde</artifactId>
+      <version>2.5.11.Final</version>
+      <exclusions>
+        <exclusion>
+              <groupId>org.apache.kafka</groupId>
+              <artifactId>kafka-clients</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.kafka</groupId>
+      <artifactId>kafka-clients</artifactId>
+      <version>3.5.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>2.0.7</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+      <version>2.0.7</version>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.11.0</version>
+        <configuration>
+          <source>17</source>
+          <target>17</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/Produce.java
 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/Produce.java
new file mode 100644
index 0000000..d10b612
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/Produce.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.acme.example.kafka;
+
+import com.acme.example.kafka.models.Product;
+import com.acme.example.kafka.models.WrongProduct;
+import io.apicurio.registry.serde.SerdeConfig;
+
+import io.apicurio.registry.serde.jsonschema.JsonSchemaKafkaSerializer;
+import org.apache.kafka.clients.producer.KafkaProducer;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.clients.producer.ProducerRecord;
+import org.apache.kafka.clients.producer.RecordMetadata;
+import org.apache.kafka.common.serialization.StringSerializer;
+import io.apicurio.registry.rest.client.exception.RestClientException;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Properties;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class Produce {
+
+    public static final String DEFAULT_PROPERTIES_PATH = 
"../application.properties";
+
+    public static void main(String[] args) throws IOException {
+        String propertiesPath = DEFAULT_PROPERTIES_PATH;
+        if (args.length >= 1) {
+            propertiesPath = args[0];
+        }
+
+        Properties properties = new Properties();
+        properties.load(Files.newInputStream(Paths.get(propertiesPath)));
+        
+        String registryUrl = properties.getProperty("schema.registry.url");
+        String authServiceUrl = properties.getProperty("keycloak.service.url");
+        String topicName = properties.getProperty("topic");
+        String authRealm = properties.getProperty("keycloak.realm");
+        String clientId = properties.getProperty("keycloak.client.id");
+        String clientSecret = properties.getProperty("keycloak.client.secret");
+        String apicurioUsername = 
properties.getProperty("keycloak.apicurio.username");
+        String apicurioPassword = 
properties.getProperty("keycloak.apicurio.password");
+
+        properties.put(SerdeConfig.REGISTRY_URL, registryUrl);
+        properties.put(SerdeConfig.AUTH_SERVICE_URL, authServiceUrl);
+        properties.put(SerdeConfig.AUTH_REALM, authRealm);
+        properties.put(SerdeConfig.AUTH_CLIENT_ID, clientId);
+        properties.put(SerdeConfig.AUTH_USERNAME, apicurioUsername);
+        properties.put(SerdeConfig.AUTH_PASSWORD, apicurioPassword);
+        properties.put(SerdeConfig.AUTH_CLIENT_SECRET, clientSecret);
+        properties.put(SerdeConfig.AUTO_REGISTER_ARTIFACT, Boolean.TRUE);
+        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, 
StringSerializer.class);
+        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, 
JsonSchemaKafkaSerializer.class);
+        properties.putIfAbsent(SerdeConfig.VALIDATION_ENABLED, Boolean.TRUE);
+
+        try (KafkaProducer<Object, Object> orderProducer = new 
KafkaProducer<>(properties)) {
+            String topic = topicName;
+            Product prod = new Product();
+            prod.setId(1);
+            prod.setName("product");
+            ProducerRecord<Object, Object> record = new 
ProducerRecord<>(topic, "test", prod);
+            WrongProduct prod1 = new WrongProduct();
+            prod1.setElement(1);
+            prod1.setText("product-wrong");
+            prod1.setDescription("Hello");
+            ProducerRecord<Object, Object> record1 = new 
ProducerRecord<>(topic, "test", prod1);
+            RecordMetadata result = orderProducer.send(record).get(5, 
TimeUnit.SECONDS);
+            System.out.println("Sent record with offset " + result.offset());
+            result = orderProducer.send(record1).get(5, TimeUnit.SECONDS);
+            System.out.println("Sent record with offset " + result.offset());
+        } catch (ExecutionException | InterruptedException | TimeoutException 
| RestClientException e ) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/models/Product.java
 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/models/Product.java
new file mode 100644
index 0000000..482348a
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/models/Product.java
@@ -0,0 +1,37 @@
+package com.acme.example.kafka.models;
+
+public class Product {
+
+    private int id;
+    private String name;
+
+    /**
+     * Constructor.
+     */
+    public Product() {
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() {
+        return "Product{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                '}';
+    }
+}
diff --git 
a/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/models/WrongProduct.java
 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/models/WrongProduct.java
new file mode 100644
index 0000000..6f6af40
--- /dev/null
+++ 
b/jbang/kafka-apicurio-secured-json-schema-registry/kafka-producer/src/main/java/com/acme/example/kafka/models/WrongProduct.java
@@ -0,0 +1,46 @@
+package com.acme.example.kafka.models;
+
+public class WrongProduct {
+
+    private int element;
+    private String text;
+    private String description;
+    /**
+     * Constructor.
+     */
+    public WrongProduct() {
+    }
+
+    public int getElement() {
+        return element;
+    }
+
+    public void setElement(int element) {
+        this.element = element;
+    }
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @Override
+    public String toString() {
+        return "WrongProduct{" +
+                "element=" + element +
+                ", text='" + text + '\'' +
+                ", description='" + description + '\'' +
+                '}';
+    }
+}

Reply via email to