This is an automated email from the ASF dual-hosted git repository.
oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
The following commit(s) were added to refs/heads/main by this push:
new 510c00b5bdf CAMEL-25185: camel-openfga-starter - add the Spring Boot
starter for the camel-openfga component (#2012)
510c00b5bdf is described below
commit 510c00b5bdf25f49f9516e8011747779c69c1a78
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Oct 1 09:58:29 2026 +0200
CAMEL-25185: camel-openfga-starter - add the Spring Boot starter for the
camel-openfga component (#2012)
camel-openfga landed on main for 4.23.0 in CAMEL-25028, so it gets a starter
alongside its companions camel-opa-starter and camel-spiffe-starter.
Hand-written: the starter pom, the META-INF LICENSE and NOTICE boilerplate,
and
registration in components-starter/pom.xml, camel-spring-boot-bom,
camel-spring-boot-dependencies and the documentation nav.
Everything else comes from camel-spring-boot-generator-maven-plugin: the
auto-configuration, configuration and converter classes,
src/main/docs/openfga.json,
the AutoConfiguration.imports entry, the catalog-provider entries and the
starter
documentation page. Thirty options bind, with connectTimeout and
readTimeout as
Long milliseconds and openFgaClient and sslContextParameters as their own
types.
OpenFgaSecurityPolicy needs no auto-configuration of its own: it is a plain
bean
rather than a component, so an application declares it as a @Bean exactly
as it
would outside Spring Boot.
Signed-off-by: Andrea Cosentino <[email protected]>
Co-authored-by: Claude Opus 5 <[email protected]>
---
.../camel/springboot/catalog/components.properties | 1 +
.../springboot/catalog/components/openfga.json | 95 ++++
components-starter/camel-openfga-starter/pom.xml | 48 ++
.../src/main/docs/openfga.json | 217 +++++++++
.../OpenFgaComponentAutoConfiguration.java | 74 +++
.../springboot/OpenFgaComponentConfiguration.java | 496 +++++++++++++++++++++
.../springboot/OpenFgaComponentConverter.java | 55 +++
.../src/main/resources/META-INF/LICENSE.txt | 203 +++++++++
.../src/main/resources/META-INF/NOTICE.txt | 11 +
...rk.boot.autoconfigure.AutoConfiguration.imports | 18 +
components-starter/pom.xml | 1 +
docs/spring-boot/modules/ROOT/nav.adoc | 1 +
.../modules/ROOT/pages/starters/openfga.adoc | 61 +++
tooling/camel-spring-boot-bom/pom.xml | 5 +
tooling/camel-spring-boot-dependencies/pom.xml | 5 +
15 files changed, 1291 insertions(+)
diff --git
a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components.properties
b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components.properties
index 190734cb010..16ebd89240c 100644
---
a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components.properties
+++
b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components.properties
@@ -288,6 +288,7 @@ olingo4
once
opa
openai
+openfga
opensearch
openshift-build-configs
openshift-builds
diff --git
a/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/openfga.json
b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/openfga.json
new file mode 100644
index 00000000000..a30e9fad22f
--- /dev/null
+++
b/catalog/camel-catalog-provider-springboot/src/main/resources/org/apache/camel/springboot/catalog/components/openfga.json
@@ -0,0 +1,95 @@
+{
+ "component": {
+ "kind": "component",
+ "name": "openfga",
+ "title": "OpenFGA",
+ "description": "Authorize an Exchange against an OpenFGA relationship
graph, and maintain the relationship tuples it is authorized against.",
+ "deprecated": false,
+ "firstVersion": "4.23.0",
+ "label": "security",
+ "javaType": "org.apache.camel.component.openfga.OpenFgaComponent",
+ "supportLevel": "Preview",
+ "groupId": "org.apache.camel.springboot",
+ "artifactId": "camel-openfga-starter",
+ "version": "4.23.0-SNAPSHOT",
+ "scheme": "openfga",
+ "extendsScheme": "",
+ "syntax": "openfga:operation",
+ "async": false,
+ "api": false,
+ "consumerOnly": false,
+ "producerOnly": true,
+ "lenientProperties": false,
+ "browsable": false,
+ "remote": true
+ },
+ "componentProperties": {
+ "apiUrl": { "index": 0, "kind": "property", "displayName": "Api Url",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "http:\/\/localhost:8080",
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The base URL of the
OpenFGA HTTP API, without a trailing path. The default ass [...]
+ "authorizationModelId": { "index": 1, "kind": "property", "displayName":
"Authorization Model Id", "group": "producer", "label": "", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The identifier of the
authorization model revision to evaluate against. Leave it empty to us [...]
+ "configuration": { "index": 2, "kind": "property", "displayName":
"Configuration", "group": "producer", "label": "", "required": false, "type":
"object", "javaType":
"org.apache.camel.component.openfga.OpenFgaConfiguration", "deprecated": false,
"autowired": false, "secret": false, "description": "The component
configuration." },
+ "consistency": { "index": 3, "kind": "property", "displayName":
"Consistency", "group": "producer", "label": "", "required": false, "type":
"enum", "javaType": "java.lang.String", "enum": [ "UNSPECIFIED",
"MINIMIZE_LATENCY", "HIGHER_CONSISTENCY" ], "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The consistency the
query is answered with. O [...]
+ "lazyStartProducer": { "index": 4, "kind": "property", "displayName":
"Lazy Start Producer", "group": "producer", "label": "producer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Whether the producer should be started lazy (on the first message). By
starting lazy you can use this to allow CamelContext and routes to startup in
situations where a producer may otherwise fail [...]
+ "object": { "index": 5, "kind": "property", "displayName": "Object",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The object being
accessed, as an OpenFGA object identifier such as {code document:budget}.
Evaluated as a Simple expressio [...]
+ "relation": { "index": 6, "kind": "property", "displayName": "Relation",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The relation to demand,
such as reader or owner. Evaluated as a Simple expression against each
exchange, though a lite [...]
+ "relations": { "index": 7, "kind": "property", "displayName": "Relations",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Comma-separated list of
relations the listRelations operation asks about, for example
reader,writer,owner. Only the [...]
+ "storeId": { "index": 8, "kind": "property", "displayName": "Store Id",
"group": "producer", "label": "", "required": true, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The identifier of the
OpenFGA store holding the relationship tuples and the authorization model,
[...]
+ "type": { "index": 9, "kind": "property", "displayName": "Type", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The object type to
enumerate for the listObjects operation, for example document. This is a type
name from the authorization m [...]
+ "user": { "index": 10, "kind": "property", "displayName": "User", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The subject to
authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as
a Simple expression against ea [...]
+ "userFilters": { "index": 11, "kind": "property", "displayName": "User
Filters", "group": "producer", "label": "", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Comma-separated list of
user filters for the listUsers operation, naming which kinds of subject to
return. An [...]
+ "autowiredEnabled": { "index": 12, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching [...]
+ "connectTimeout": { "index": 13, "kind": "property", "displayName":
"Connect Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "duration", "javaType": "long", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "10000", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How long to wait for the
connection to OpenFGA to be established. The component a [...]
+ "maxParallelRequests": { "index": 14, "kind": "property", "displayName":
"Max Parallel Requests", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 10, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How many of a
batchCheck's checks may be in flight at once. The batch is issu [...]
+ "maxRetries": { "index": 15, "kind": "property", "displayName": "Max
Retries", "group": "advanced", "label": "advanced", "required": false, "type":
"integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 3, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How many times the SDK
retries a request that failed in a way worth retrying, such as a rate limi [...]
+ "openFgaClient": { "index": 16, "kind": "property", "displayName": "Open
Fga Client", "group": "advanced", "label": "advanced", "required": false,
"type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "An existing
OpenFgaClient to use. When set, every o [...]
+ "readTimeout": { "index": 17, "kind": "property", "displayName": "Read
Timeout", "group": "advanced", "label": "advanced", "required": false, "type":
"duration", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "10000", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How long to wait for one
request to OpenFGA to complete once connected. A request that [...]
+ "healthCheckConsumerEnabled": { "index": 18, "kind": "property",
"displayName": "Health Check Consumer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all consumer based health checks
from this component" },
+ "healthCheckProducerEnabled": { "index": 19, "kind": "property",
"displayName": "Health Check Producer Enabled", "group": "health", "label":
"health", "required": false, "type": "boolean", "javaType": "boolean",
"deprecated": false, "autowired": false, "secret": false, "defaultValue": true,
"description": "Used for enabling or disabling all producer based health checks
from this component. Notice: Camel has by default disabled all producer based
health-checks. You can turn on produce [...]
+ "apiAudience": { "index": 20, "kind": "property", "displayName": "Api
Audience", "group": "security", "label": "security", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The audience to request
the access token for in the client-credentials flow." },
+ "apiToken": { "index": 21, "kind": "property", "displayName": "Api Token",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Pre-shared token sent to
OpenFGA in the Authorization header, for a server started with [...]
+ "apiTokenIssuer": { "index": 22, "kind": "property", "displayName": "Api
Token Issuer", "group": "security", "label": "security", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The token endpoint the
client-credentials flow exchanges its credentials at." },
+ "clientId": { "index": 23, "kind": "property", "displayName": "Client Id",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Client identifier for
the OAuth 2.0 client-credentials flow, for a server that authenticates through
an OIDC [...]
+ "clientSecret": { "index": 24, "kind": "property", "displayName": "Client
Secret", "group": "security", "label": "security", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Client secret for the
OAuth 2.0 client-credentials flow." },
+ "failOpen": { "index": 25, "kind": "property", "displayName": "Fail Open",
"group": "security", "label": "security", "required": false, "type": "boolean",
"javaType": "boolean", "deprecated": false, "autowired": false, "secret":
false, "security": "insecure:dev", "defaultValue": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Whether to let the
exchange proceed when OpenFGA could not be ask [...]
+ "scopes": { "index": 26, "kind": "property", "displayName": "Scopes",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Space-separated scopes
to request in the client-credentials flow." },
+ "sslContextParameters": { "index": 27, "kind": "property", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "TLS configuration for
the connection to OpenFGA. [...]
+ "useGlobalSslContextParameters": { "index": 28, "kind": "property",
"displayName": "Use Global Ssl Context Parameters", "group": "security",
"label": "security", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Enable usage of global SSL context
parameters." }
+ },
+ "headers": {
+ "CamelOpenFgaAllowed": { "index": 0, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"Boolean", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The allow\/deny verdict of the authorization
check. Always overwritten by the component, so a value set by an inbound
message never survives into the route.", "constantName":
"org.apache.camel.component.openfga.OpenFgaConstants#ALLOWED" },
+ "CamelOpenFgaDenyReason": { "index": 1, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "Why the exchange was denied, set only on a
deny. denied when OpenFGA evaluated the relationship and answered no;
missing-user, missing-object, missing-relation, wildcard-subject or
invalid-identifier when the exchange never reached [...]
+ "CamelOpenFgaFailedOpen": { "index": 2, "kind": "header", "displayName":
"", "group": "producer", "label": "producer", "required": false, "javaType":
"Boolean", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "Set to true only when the exchange proceeded
because failOpen is enabled and OpenFGA could not be asked - nothing authorized
it. Absent on every verdict OpenFGA actually gave, so a route or an audit trail
can tell the two apart ra [...]
+ "CamelOpenFgaUser": { "index": 3, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The subject the check was made for, as
resolved from the endpoint's user expression. Set for observability; it is not
read as an input.", "constantName":
"org.apache.camel.component.openfga.OpenFgaConstants#USER" },
+ "CamelOpenFgaObject": { "index": 4, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The object the check was made against, as
resolved from the endpoint's object expression. Set for observability; it is
not read as an input.", "constantName":
"org.apache.camel.component.openfga.OpenFgaConstants#OBJECT" },
+ "CamelOpenFgaRelation": { "index": 5, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The relation that was checked. Set for
observability; it is not read as an input and cannot be used to demand a weaker
permission than the endpoint configured.", "constantName":
"org.apache.camel.component.openfga.OpenFgaConstants#RE [...]
+ "CamelOpenFgaStoreId": { "index": 6, "kind": "header", "displayName": "",
"group": "producer", "label": "producer", "required": false, "javaType":
"String", "deprecated": false, "deprecationNote": "", "autowired": false,
"secret": false, "description": "The identifier of the OpenFGA store that was
consulted, so an audit trail records which relationship graph produced the
verdict.", "constantName":
"org.apache.camel.component.openfga.OpenFgaConstants#STORE_ID" },
+ "CamelOpenFgaWrittenTuples": { "index": 7, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "How many relationship tuples the
writeTuples operation wrote.", "constantName":
"org.apache.camel.component.openfga.OpenFgaConstants#WRITTEN_TUPLES" },
+ "CamelOpenFgaDeletedTuples": { "index": 8, "kind": "header",
"displayName": "", "group": "producer", "label": "producer", "required": false,
"javaType": "Integer", "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "How many relationship tuples the
deleteTuples operation deleted.", "constantName":
"org.apache.camel.component.openfga.OpenFgaConstants#DELETED_TUPLES" }
+ },
+ "properties": {
+ "operation": { "index": 0, "kind": "path", "displayName": "Operation",
"group": "producer", "label": "", "required": true, "type": "enum", "javaType":
"org.apache.camel.component.openfga.OpenFgaOperation", "enum": [ "check",
"batchCheck", "listObjects", "listRelations", "listUsers", "writeTuples",
"deleteTuples" ], "deprecated": false, "deprecationNote": "", "autowired":
false, "secret": false, "description": "The operation to perform. The operation
is taken from the endpoint only: i [...]
+ "apiUrl": { "index": 1, "kind": "parameter", "displayName": "Api Url",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "http:\/\/localhost:8080",
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The base URL of the
OpenFGA HTTP API, without a trailing path. The default as [...]
+ "authorizationModelId": { "index": 2, "kind": "parameter", "displayName":
"Authorization Model Id", "group": "producer", "label": "", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The identifier of the
authorization model revision to evaluate against. Leave it empty to u [...]
+ "consistency": { "index": 3, "kind": "parameter", "displayName":
"Consistency", "group": "producer", "label": "", "required": false, "type":
"enum", "javaType": "java.lang.String", "enum": [ "UNSPECIFIED",
"MINIMIZE_LATENCY", "HIGHER_CONSISTENCY" ], "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The consistency the
query is answered with. [...]
+ "object": { "index": 4, "kind": "parameter", "displayName": "Object",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The object being
accessed, as an OpenFGA object identifier such as {code document:budget}.
Evaluated as a Simple expressi [...]
+ "relation": { "index": 5, "kind": "parameter", "displayName": "Relation",
"group": "producer", "label": "", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The relation to demand,
such as reader or owner. Evaluated as a Simple expression against each
exchange, though a lit [...]
+ "relations": { "index": 6, "kind": "parameter", "displayName":
"Relations", "group": "producer", "label": "", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Comma-separated list of
relations the listRelations operation asks about, for example
reader,writer,owner. Only the [...]
+ "storeId": { "index": 7, "kind": "parameter", "displayName": "Store Id",
"group": "producer", "label": "", "required": true, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "",
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The identifier of the
OpenFGA store holding the relationship tuples and the authorization model, [...]
+ "type": { "index": 8, "kind": "parameter", "displayName": "Type", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The object type to
enumerate for the listObjects operation, for example document. This is a type
name from the authorization [...]
+ "user": { "index": 9, "kind": "parameter", "displayName": "User", "group":
"producer", "label": "", "required": false, "type": "string", "javaType":
"java.lang.String", "deprecated": false, "autowired": false, "secret": false,
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The subject to
authorize, as an OpenFGA user identifier such as {code user:anne}. Evaluated as
a Simple expression against ea [...]
+ "userFilters": { "index": 10, "kind": "parameter", "displayName": "User
Filters", "group": "producer", "label": "", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Comma-separated list of
user filters for the listUsers operation, naming which kinds of subject to
return. An [...]
+ "lazyStartProducer": { "index": 11, "kind": "parameter", "displayName":
"Lazy Start Producer", "group": "producer (advanced)", "label":
"producer,advanced", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "Whether the producer should be started
lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a produ [...]
+ "connectTimeout": { "index": 12, "kind": "parameter", "displayName":
"Connect Timeout", "group": "advanced", "label": "advanced", "required": false,
"type": "duration", "javaType": "long", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": "10000", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How long to wait for the
connection to OpenFGA to be established. The component [...]
+ "maxParallelRequests": { "index": 13, "kind": "parameter", "displayName":
"Max Parallel Requests", "group": "advanced", "label": "advanced", "required":
false, "type": "integer", "javaType": "int", "deprecated": false, "autowired":
false, "secret": false, "defaultValue": 10, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How many of a
batchCheck's checks may be in flight at once. The batch is iss [...]
+ "maxRetries": { "index": 14, "kind": "parameter", "displayName": "Max
Retries", "group": "advanced", "label": "advanced", "required": false, "type":
"integer", "javaType": "int", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": 3, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How many times the SDK
retries a request that failed in a way worth retrying, such as a rate lim [...]
+ "openFgaClient": { "index": 15, "kind": "parameter", "displayName": "Open
Fga Client", "group": "advanced", "label": "advanced", "required": false,
"type": "object", "javaType": "dev.openfga.sdk.api.client.OpenFgaClient",
"deprecated": false, "deprecationNote": "", "autowired": true, "secret": false,
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "An existing
OpenFgaClient to use. When set, every [...]
+ "readTimeout": { "index": 16, "kind": "parameter", "displayName": "Read
Timeout", "group": "advanced", "label": "advanced", "required": false, "type":
"duration", "javaType": "long", "deprecated": false, "autowired": false,
"secret": false, "defaultValue": "10000", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "How long to wait for one
request to OpenFGA to complete once connected. A request that [...]
+ "apiAudience": { "index": 17, "kind": "parameter", "displayName": "Api
Audience", "group": "security", "label": "security", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The audience to request
the access token for in the client-credentials flow." },
+ "apiToken": { "index": 18, "kind": "parameter", "displayName": "Api
Token", "group": "security", "label": "security", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Pre-shared token sent to
OpenFGA in the Authorization header, for a server started wit [...]
+ "apiTokenIssuer": { "index": 19, "kind": "parameter", "displayName": "Api
Token Issuer", "group": "security", "label": "security", "required": false,
"type": "string", "javaType": "java.lang.String", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "The token endpoint the
client-credentials flow exchanges its credentials at." },
+ "clientId": { "index": 20, "kind": "parameter", "displayName": "Client
Id", "group": "security", "label": "security", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Client identifier for
the OAuth 2.0 client-credentials flow, for a server that authenticates through
an OID [...]
+ "clientSecret": { "index": 21, "kind": "parameter", "displayName": "Client
Secret", "group": "security", "label": "security", "required": false, "type":
"string", "javaType": "java.lang.String", "deprecated": false, "autowired":
false, "secret": true, "security": "secret", "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Client secret for the
OAuth 2.0 client-credentials flow." },
+ "failOpen": { "index": 22, "kind": "parameter", "displayName": "Fail
Open", "group": "security", "label": "security", "required": false, "type":
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false,
"secret": false, "security": "insecure:dev", "defaultValue": false,
"configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Whether to let the
exchange proceed when OpenFGA could not be as [...]
+ "scopes": { "index": 23, "kind": "parameter", "displayName": "Scopes",
"group": "security", "label": "security", "required": false, "type": "string",
"javaType": "java.lang.String", "deprecated": false, "autowired": false,
"secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "Space-separated scopes
to request in the client-credentials flow." },
+ "sslContextParameters": { "index": 24, "kind": "parameter", "displayName":
"Ssl Context Parameters", "group": "security", "label": "security", "required":
false, "type": "object", "javaType":
"org.apache.camel.support.jsse.SSLContextParameters", "deprecated": false,
"autowired": false, "secret": false, "configurationClass":
"org.apache.camel.component.openfga.OpenFgaConfiguration",
"configurationField": "configuration", "description": "TLS configuration for
the connection to OpenFGA. [...]
+ }
+}
diff --git a/components-starter/camel-openfga-starter/pom.xml
b/components-starter/camel-openfga-starter/pom.xml
new file mode 100644
index 00000000000..d5d45d30392
--- /dev/null
+++ b/components-starter/camel-openfga-starter/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<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>
+ <parent>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>components-starter</artifactId>
+ <version>4.23.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>camel-openfga-starter</artifactId>
+ <packaging>jar</packaging>
+ <name>Camel SB Starters :: OpenFGA</name>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter</artifactId>
+ <version>${spring-boot-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-openfga</artifactId>
+ <version>${camel-version}</version>
+ </dependency>
+ <!--START OF GENERATED CODE-->
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-core-starter</artifactId>
+ </dependency>
+ <!--END OF GENERATED CODE-->
+ </dependencies>
+</project>
diff --git
a/components-starter/camel-openfga-starter/src/main/docs/openfga.json
b/components-starter/camel-openfga-starter/src/main/docs/openfga.json
new file mode 100644
index 00000000000..22150f986b2
--- /dev/null
+++ b/components-starter/camel-openfga-starter/src/main/docs/openfga.json
@@ -0,0 +1,217 @@
+{
+ "groups": [
+ {
+ "name": "camel.component.openfga",
+ "type":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.customizer",
+ "type":
"org.apache.camel.spring.boot.ComponentConfigurationPropertiesCommon$CustomizerProperties",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "sourceMethod": "getCustomizer()"
+ }
+ ],
+ "properties": [
+ {
+ "name": "camel.component.openfga.api-audience",
+ "type": "java.lang.String",
+ "description": "The audience to request the access token for in the
client-credentials flow.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.api-token",
+ "type": "java.lang.String",
+ "description": "Pre-shared token sent to OpenFGA in the Authorization
header, for a server started with {code --authn-method preshared}.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.api-token-issuer",
+ "type": "java.lang.String",
+ "description": "The token endpoint the client-credentials flow exchanges
its credentials at.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.api-url",
+ "type": "java.lang.String",
+ "description": "The base URL of the OpenFGA HTTP API, without a trailing
path. The default assumes OpenFGA running as a sidecar on its standard HTTP
port.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": "http:\/\/localhost:8080"
+ },
+ {
+ "name": "camel.component.openfga.authorization-model-id",
+ "type": "java.lang.String",
+ "description": "The identifier of the authorization model revision to
evaluate against. Leave it empty to use whichever model the store considers
latest. Pin it in production. A store keeps every model it was ever given and
latest moves the moment somebody writes a new one, so an unpinned endpoint can
start answering a different question than the one it was reviewed with -
without any change to the route. Pinning also makes a model rollout a
deliberate, reviewable configuration change.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.autowired-enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether autowiring is enabled. This is used for
automatic autowiring options (the option must be marked as autowired) by
looking up in the registry to find if there is a single instance of matching
type, which then gets configured on the component. This can be used for
automatic configuring JDBC data sources, JMS connection factories, AWS Clients,
etc.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": true
+ },
+ {
+ "name": "camel.component.openfga.client-id",
+ "type": "java.lang.String",
+ "description": "Client identifier for the OAuth 2.0 client-credentials
flow, for a server that authenticates through an OIDC provider. Setting it
selects that flow, so clientSecret, apiTokenIssuer and apiAudience are then
required too.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.client-secret",
+ "type": "java.lang.String",
+ "description": "Client secret for the OAuth 2.0 client-credentials
flow.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.configuration",
+ "type": "org.apache.camel.component.openfga.OpenFgaConfiguration",
+ "description": "The component configuration. The option is a
org.apache.camel.component.openfga.OpenFgaConfiguration type.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.connect-timeout",
+ "type": "java.lang.Long",
+ "description": "How long to wait for the connection to OpenFGA to be
established. The component applies this itself rather than through the SDK's
own connectTimeout setting, which as of openfga-sdk 0.10.1 is accepted and then
never read, leaving the connect phase bounded only by the operating system. The
option is a long type.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": 10000
+ },
+ {
+ "name": "camel.component.openfga.consistency",
+ "type": "java.lang.String",
+ "description": "The consistency the query is answered with. OpenFGA's
default, MINIMIZE_LATENCY, may answer from a replica that has not caught up
yet, which right after a revoke means a tuple that was deleted can still grant
access for a moment. Set HIGHER_CONSISTENCY on the paths where that window
matters, at the cost of latency. Left unset, OpenFGA's own default applies.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.customizer.enabled",
+ "type": "java.lang.Boolean",
+ "sourceType":
"org.apache.camel.spring.boot.ComponentConfigurationPropertiesCommon$CustomizerProperties"
+ },
+ {
+ "name": "camel.component.openfga.enabled",
+ "type": "java.lang.Boolean",
+ "description": "Whether to enable auto configuration of the openfga
component. This is enabled by default.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.fail-open",
+ "type": "java.lang.Boolean",
+ "description": "Whether to let the exchange proceed when OpenFGA could
not be asked at all, for example because the server is unreachable. Disabled by
default so that an unavailable decision point denies rather than grants access.
Do not enable this in production. It applies to the check operation and to
OpenFgaSecurityPolicy, the two places where proceed has a meaning, and it
covers only a failure to obtain a verdict. An exchange that was denied, and an
exchange that carried no us [...]
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": false
+ },
+ {
+ "name": "camel.component.openfga.health-check-consumer-enabled",
+ "type": "java.lang.Boolean",
+ "description": "Used for enabling or disabling all consumer based health
checks from this component",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": true
+ },
+ {
+ "name": "camel.component.openfga.health-check-producer-enabled",
+ "type": "java.lang.Boolean",
+ "description": "Used for enabling or disabling all producer based health
checks from this component. Notice: Camel has by default disabled all producer
based health-checks. You can turn on producer checks globally by setting
camel.health.producersEnabled=true.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": true
+ },
+ {
+ "name": "camel.component.openfga.lazy-start-producer",
+ "type": "java.lang.Boolean",
+ "description": "Whether the producer should be started lazy (on the
first message). By starting lazy you can use this to allow CamelContext and
routes to startup in situations where a producer may otherwise fail during
starting and cause the route to fail being started. By deferring this startup
to be lazy then the startup failure can be handled during routing messages via
Camel's routing error handlers. Beware that when the first message is processed
then creating and starting the [...]
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": false
+ },
+ {
+ "name": "camel.component.openfga.max-parallel-requests",
+ "type": "java.lang.Integer",
+ "description": "How many of a batchCheck's checks may be in flight at
once. The batch is issued as one request per object, so this bounds the load
one exchange puts on the server.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": 10
+ },
+ {
+ "name": "camel.component.openfga.max-retries",
+ "type": "java.lang.Integer",
+ "description": "How many times the SDK retries a request that failed in
a way worth retrying, such as a rate limit or a 5xx. Set it to 0 to disable
retries; the overall wait a routing thread can spend on one exchange grows with
it.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": 3
+ },
+ {
+ "name": "camel.component.openfga.object",
+ "type": "java.lang.String",
+ "description": "The object being accessed, as an OpenFGA object
identifier such as {code document:budget}. Evaluated as a Simple expression
against each exchange, so document:${header.documentId} names the resource the
message is about. Unlike the subject, taking the object from a header is normal
and safe: the caller is entitled to say which resource it wants, and the check
is what decides whether it may have it.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.open-fga-client",
+ "type": "dev.openfga.sdk.api.client.OpenFgaClient",
+ "description": "An existing OpenFgaClient to use. When set, every option
describing how to reach the server - apiUrl, storeId, the credentials, the
timeouts and sslContextParameters - is ignored, because they are baked into the
client that was handed over. The option is a
dev.openfga.sdk.api.client.OpenFgaClient type.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.read-timeout",
+ "type": "java.lang.Long",
+ "description": "How long to wait for one request to OpenFGA to complete
once connected. A request that times out is a failure to obtain a verdict
rather than a deny, so it fails closed - or proceeds when failOpen is set. The
option is a long type.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": 10000
+ },
+ {
+ "name": "camel.component.openfga.relation",
+ "type": "java.lang.String",
+ "description": "The relation to demand, such as reader or owner.
Evaluated as a Simple expression against each exchange, though a literal is
what you usually want. The relation is the permission being demanded, so
resolving it from an inbound header lets the caller pick the weakest one the
model defines. Keep it literal, or derive it from something the route controls
such as ${header.CamelHttpMethod}.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.relations",
+ "type": "java.lang.String",
+ "description": "Comma-separated list of relations the listRelations
operation asks about, for example reader,writer,owner. Only the ones the
subject actually holds come back.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.scopes",
+ "type": "java.lang.String",
+ "description": "Space-separated scopes to request in the
client-credentials flow.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.ssl-context-parameters",
+ "type": "org.apache.camel.support.jsse.SSLContextParameters",
+ "description": "TLS configuration for the connection to OpenFGA. Needed
to trust a server whose certificate comes from a private CA, and to present a
client certificate to a server that requires mutual TLS - a SPIFFE X.509-SVID
obtained with {code camel-spiffe}, for instance, so the workload authenticates
to the decision point as itself. The option is a
org.apache.camel.support.jsse.SSLContextParameters type.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.store-id",
+ "type": "java.lang.String",
+ "description": "The identifier of the OpenFGA store holding the
relationship tuples and the authorization model, as returned by {code fga store
create}. The store is the relationship graph that judges the exchange, so it
comes from the endpoint only and is never taken from a message header.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.type",
+ "type": "java.lang.String",
+ "description": "The object type to enumerate for the listObjects
operation, for example document. This is a type name from the authorization
model, so it is taken literally rather than evaluated.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.use-global-ssl-context-parameters",
+ "type": "java.lang.Boolean",
+ "description": "Enable usage of global SSL context parameters.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration",
+ "defaultValue": false
+ },
+ {
+ "name": "camel.component.openfga.user",
+ "type": "java.lang.String",
+ "description": "The subject to authorize, as an OpenFGA user identifier
such as {code user:anne}. Evaluated as a Simple expression against each
exchange, so a literal is used as-is and
user:${exchangeProperty.CamelKeycloakTokenSubject} resolves whatever an earlier
step established. Read it from an exchange property rather than a header
wherever you can. An exchange property is set by the route itself - by the step
that verified the caller - and nothing outside the route can set one [...]
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ },
+ {
+ "name": "camel.component.openfga.user-filters",
+ "type": "java.lang.String",
+ "description": "Comma-separated list of user filters for the listUsers
operation, naming which kinds of subject to return. An entry is either a type,
user, or a type and a relation, team#member, to return the usersets holding the
relation rather than the individual subjects. Defaults to user.",
+ "sourceType":
"org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration"
+ }
+ ],
+ "hints": [],
+ "ignored": {
+ "properties": []
+ }
+}
\ No newline at end of file
diff --git
a/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentAutoConfiguration.java
b/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentAutoConfiguration.java
new file mode 100644
index 00000000000..908b0097fa1
--- /dev/null
+++
b/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentAutoConfiguration.java
@@ -0,0 +1,74 @@
+/*
+ * 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 org.apache.camel.component.openfga.springboot;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+import org.apache.camel.component.openfga.OpenFgaComponent;
+import org.apache.camel.spi.ComponentCustomizer;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.spring.boot.ComponentConfigurationProperties;
+import org.apache.camel.spring.boot.util.CamelPropertiesHelper;
+import
org.apache.camel.spring.boot.util.ConditionalOnCamelContextAndAutoConfigurationBeans;
+import org.apache.camel.spring.boot.util.ConditionalOnHierarchicalProperties;
+import org.apache.camel.spring.boot.util.HierarchicalPropertiesEvaluator;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import
org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Lazy;
+
+/**
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@AutoConfiguration(after = {CamelAutoConfiguration.class,
OpenFgaComponentConverter.class})
+@Conditional(ConditionalOnCamelContextAndAutoConfigurationBeans.class)
+@EnableConfigurationProperties({ComponentConfigurationProperties.class,OpenFgaComponentConfiguration.class})
+@ConditionalOnHierarchicalProperties({"camel.component",
"camel.component.openfga"})
+public class OpenFgaComponentAutoConfiguration {
+
+ private final ApplicationContext applicationContext;
+ private final OpenFgaComponentConfiguration configuration;
+
+ public OpenFgaComponentAutoConfiguration(
+ org.springframework.context.ApplicationContext applicationContext,
+
org.apache.camel.component.openfga.springboot.OpenFgaComponentConfiguration
configuration) {
+ this.applicationContext = applicationContext;
+ this.configuration = configuration;
+ }
+
+ @Lazy
+ @Bean
+ public ComponentCustomizer configureOpenFgaComponent() {
+ return new ComponentCustomizer() {
+ @Override
+ public void configure(String name, Component target) {
+
CamelPropertiesHelper.copyConfigurationProperties(target.getCamelContext(),
applicationContext,
+ "camel.component.openfga", configuration, target);
+ }
+ @Override
+ public boolean isEnabled(String name, Component target) {
+ return HierarchicalPropertiesEvaluator.evaluate(
+ applicationContext,
+ "camel.component.customizer",
+ "camel.component.openfga.customizer")
+ && target instanceof OpenFgaComponent;
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git
a/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentConfiguration.java
b/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentConfiguration.java
new file mode 100644
index 00000000000..f4616dcb2ec
--- /dev/null
+++
b/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentConfiguration.java
@@ -0,0 +1,496 @@
+/*
+ * 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 org.apache.camel.component.openfga.springboot;
+
+import dev.openfga.sdk.api.client.OpenFgaClient;
+import org.apache.camel.component.openfga.OpenFgaConfiguration;
+import org.apache.camel.spring.boot.ComponentConfigurationPropertiesCommon;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Authorize an Exchange against an OpenFGA relationship graph, and maintain
the
+ * relationship tuples it is authorized against.
+ *
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@ConfigurationProperties(prefix = "camel.component.openfga")
+public class OpenFgaComponentConfiguration
+ extends
+ ComponentConfigurationPropertiesCommon {
+
+ /**
+ * Whether to enable auto configuration of the openfga component. This is
+ * enabled by default.
+ */
+ private Boolean enabled;
+ /**
+ * The base URL of the OpenFGA HTTP API, without a trailing path. The
+ * default assumes OpenFGA running as a sidecar on its standard HTTP port.
+ */
+ private String apiUrl = "http://localhost:8080";
+ /**
+ * The identifier of the authorization model revision to evaluate against.
+ * Leave it empty to use whichever model the store considers latest. Pin it
+ * in production. A store keeps every model it was ever given and latest
+ * moves the moment somebody writes a new one, so an unpinned endpoint can
+ * start answering a different question than the one it was reviewed with -
+ * without any change to the route. Pinning also makes a model rollout a
+ * deliberate, reviewable configuration change.
+ */
+ private String authorizationModelId;
+ /**
+ * The component configuration. The option is a
+ * org.apache.camel.component.openfga.OpenFgaConfiguration type.
+ */
+ private OpenFgaConfiguration configuration;
+ /**
+ * The consistency the query is answered with. OpenFGA's default,
+ * MINIMIZE_LATENCY, may answer from a replica that has not caught up yet,
+ * which right after a revoke means a tuple that was deleted can still
grant
+ * access for a moment. Set HIGHER_CONSISTENCY on the paths where that
+ * window matters, at the cost of latency. Left unset, OpenFGA's own
default
+ * applies.
+ */
+ private String consistency;
+ /**
+ * Whether the producer should be started lazy (on the first message). By
+ * starting lazy you can use this to allow CamelContext and routes to
+ * startup in situations where a producer may otherwise fail during
starting
+ * and cause the route to fail being started. By deferring this startup to
+ * be lazy then the startup failure can be handled during routing messages
+ * via Camel's routing error handlers. Beware that when the first message
is
+ * processed then creating and starting the producer may take a little time
+ * and prolong the total processing time of the processing.
+ */
+ private Boolean lazyStartProducer = false;
+ /**
+ * The object being accessed, as an OpenFGA object identifier such as {code
+ * document:budget}. Evaluated as a Simple expression against each
exchange,
+ * so document:${header.documentId} names the resource the message is
about.
+ * Unlike the subject, taking the object from a header is normal and safe:
+ * the caller is entitled to say which resource it wants, and the check is
+ * what decides whether it may have it.
+ */
+ private String object;
+ /**
+ * The relation to demand, such as reader or owner. Evaluated as a Simple
+ * expression against each exchange, though a literal is what you usually
+ * want. The relation is the permission being demanded, so resolving it
from
+ * an inbound header lets the caller pick the weakest one the model
defines.
+ * Keep it literal, or derive it from something the route controls such as
+ * ${header.CamelHttpMethod}.
+ */
+ private String relation;
+ /**
+ * Comma-separated list of relations the listRelations operation asks
about,
+ * for example reader,writer,owner. Only the ones the subject actually
holds
+ * come back.
+ */
+ private String relations;
+ /**
+ * The identifier of the OpenFGA store holding the relationship tuples and
+ * the authorization model, as returned by {code fga store create}. The
+ * store is the relationship graph that judges the exchange, so it comes
+ * from the endpoint only and is never taken from a message header.
+ */
+ private String storeId;
+ /**
+ * The object type to enumerate for the listObjects operation, for example
+ * document. This is a type name from the authorization model, so it is
+ * taken literally rather than evaluated.
+ */
+ private String type;
+ /**
+ * The subject to authorize, as an OpenFGA user identifier such as {code
+ * user:anne}. Evaluated as a Simple expression against each exchange, so a
+ * literal is used as-is and
+ * user:${exchangeProperty.CamelKeycloakTokenSubject} resolves whatever an
+ * earlier step established. Read it from an exchange property rather than
a
+ * header wherever you can. An exchange property is set by the route itself
+ * - by the step that verified the caller - and nothing outside the route
+ * can set one. A header, by contrast, is often whatever the caller sent,
+ * and an endpoint configured as user:${header.userId} lets the caller
+ * choose who to be. {code camel-keycloak}'s KeycloakSecurityPolicy already
+ * follows that reasoning: it reads the subject from the
+ * CamelKeycloakTokenSubject exchange property in preference to the header
+ * of the same name, its preferPropertyOverHeader option defaulting to
true.
+ * Nothing in Camel sets the property for you, so the step that validates
+ * the token has to record it - but recording it under that name lets one
+ * identity serve both. An expression that resolves to blank, or to a bare
+ * {code user:} prefix, denies the exchange: an exchange carrying no
+ * identity is not authorized, and failOpen does not apply to it.
+ */
+ private String user;
+ /**
+ * Comma-separated list of user filters for the listUsers operation, naming
+ * which kinds of subject to return. An entry is either a type, user, or a
+ * type and a relation, team#member, to return the usersets holding the
+ * relation rather than the individual subjects. Defaults to user.
+ */
+ private String userFilters;
+ /**
+ * Whether autowiring is enabled. This is used for automatic autowiring
+ * options (the option must be marked as autowired) by looking up in the
+ * registry to find if there is a single instance of matching type, which
+ * then gets configured on the component. This can be used for automatic
+ * configuring JDBC data sources, JMS connection factories, AWS Clients,
+ * etc.
+ */
+ private Boolean autowiredEnabled = true;
+ /**
+ * How long to wait for the connection to OpenFGA to be established. The
+ * component applies this itself rather than through the SDK's own
+ * connectTimeout setting, which as of openfga-sdk 0.10.1 is accepted and
+ * then never read, leaving the connect phase bounded only by the operating
+ * system. The option is a long type.
+ */
+ private Long connectTimeout = 10000L;
+ /**
+ * How many of a batchCheck's checks may be in flight at once. The batch is
+ * issued as one request per object, so this bounds the load one exchange
+ * puts on the server.
+ */
+ private Integer maxParallelRequests = 10;
+ /**
+ * How many times the SDK retries a request that failed in a way worth
+ * retrying, such as a rate limit or a 5xx. Set it to 0 to disable retries;
+ * the overall wait a routing thread can spend on one exchange grows with
+ * it.
+ */
+ private Integer maxRetries = 3;
+ /**
+ * An existing OpenFgaClient to use. When set, every option describing how
+ * to reach the server - apiUrl, storeId, the credentials, the timeouts and
+ * sslContextParameters - is ignored, because they are baked into the
client
+ * that was handed over. The option is a
+ * dev.openfga.sdk.api.client.OpenFgaClient type.
+ */
+ private OpenFgaClient openFgaClient;
+ /**
+ * How long to wait for one request to OpenFGA to complete once connected.
A
+ * request that times out is a failure to obtain a verdict rather than a
+ * deny, so it fails closed - or proceeds when failOpen is set. The option
+ * is a long type.
+ */
+ private Long readTimeout = 10000L;
+ /**
+ * Used for enabling or disabling all consumer based health checks from
this
+ * component
+ */
+ private Boolean healthCheckConsumerEnabled = true;
+ /**
+ * Used for enabling or disabling all producer based health checks from
this
+ * component. Notice: Camel has by default disabled all producer based
+ * health-checks. You can turn on producer checks globally by setting
+ * camel.health.producersEnabled=true.
+ */
+ private Boolean healthCheckProducerEnabled = true;
+ /**
+ * The audience to request the access token for in the client-credentials
+ * flow.
+ */
+ private String apiAudience;
+ /**
+ * Pre-shared token sent to OpenFGA in the Authorization header, for a
+ * server started with {code --authn-method preshared}.
+ */
+ private String apiToken;
+ /**
+ * The token endpoint the client-credentials flow exchanges its credentials
+ * at.
+ */
+ private String apiTokenIssuer;
+ /**
+ * Client identifier for the OAuth 2.0 client-credentials flow, for a
server
+ * that authenticates through an OIDC provider. Setting it selects that
+ * flow, so clientSecret, apiTokenIssuer and apiAudience are then required
+ * too.
+ */
+ private String clientId;
+ /**
+ * Client secret for the OAuth 2.0 client-credentials flow.
+ */
+ private String clientSecret;
+ /**
+ * Whether to let the exchange proceed when OpenFGA could not be asked at
+ * all, for example because the server is unreachable. Disabled by default
+ * so that an unavailable decision point denies rather than grants access.
+ * Do not enable this in production. It applies to the check operation and
+ * to OpenFgaSecurityPolicy, the two places where proceed has a meaning,
and
+ * it covers only a failure to obtain a verdict. An exchange that was
+ * denied, and an exchange that carried no usable subject or object, are
+ * decisions rather than failures and are never turned into an allow by
this
+ * flag. The other operations ignore it. A batchCheck or listObjects that
+ * failed has no safe way to proceed - returning the objects it never
+ * managed to filter would be the leak the filtering was there to prevent -
+ * so a failure there is reported as an error for the route's own error
+ * handling to deal with.
+ */
+ private Boolean failOpen = false;
+ /**
+ * Space-separated scopes to request in the client-credentials flow.
+ */
+ private String scopes;
+ /**
+ * TLS configuration for the connection to OpenFGA. Needed to trust a
server
+ * whose certificate comes from a private CA, and to present a client
+ * certificate to a server that requires mutual TLS - a SPIFFE X.509-SVID
+ * obtained with {code camel-spiffe}, for instance, so the workload
+ * authenticates to the decision point as itself. The option is a
+ * org.apache.camel.support.jsse.SSLContextParameters type.
+ */
+ private SSLContextParameters sslContextParameters;
+ /**
+ * Enable usage of global SSL context parameters.
+ */
+ private Boolean useGlobalSslContextParameters = false;
+
+ public String getApiUrl() {
+ return apiUrl;
+ }
+
+ public void setApiUrl(String apiUrl) {
+ this.apiUrl = apiUrl;
+ }
+
+ public String getAuthorizationModelId() {
+ return authorizationModelId;
+ }
+
+ public void setAuthorizationModelId(String authorizationModelId) {
+ this.authorizationModelId = authorizationModelId;
+ }
+
+ public OpenFgaConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ public void setConfiguration(OpenFgaConfiguration configuration) {
+ this.configuration = configuration;
+ }
+
+ public String getConsistency() {
+ return consistency;
+ }
+
+ public void setConsistency(String consistency) {
+ this.consistency = consistency;
+ }
+
+ public Boolean getLazyStartProducer() {
+ return lazyStartProducer;
+ }
+
+ public void setLazyStartProducer(Boolean lazyStartProducer) {
+ this.lazyStartProducer = lazyStartProducer;
+ }
+
+ public String getObject() {
+ return object;
+ }
+
+ public void setObject(String object) {
+ this.object = object;
+ }
+
+ public String getRelation() {
+ return relation;
+ }
+
+ public void setRelation(String relation) {
+ this.relation = relation;
+ }
+
+ public String getRelations() {
+ return relations;
+ }
+
+ public void setRelations(String relations) {
+ this.relations = relations;
+ }
+
+ public String getStoreId() {
+ return storeId;
+ }
+
+ public void setStoreId(String storeId) {
+ this.storeId = storeId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public String getUserFilters() {
+ return userFilters;
+ }
+
+ public void setUserFilters(String userFilters) {
+ this.userFilters = userFilters;
+ }
+
+ public Boolean getAutowiredEnabled() {
+ return autowiredEnabled;
+ }
+
+ public void setAutowiredEnabled(Boolean autowiredEnabled) {
+ this.autowiredEnabled = autowiredEnabled;
+ }
+
+ public Long getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ public void setConnectTimeout(Long connectTimeout) {
+ this.connectTimeout = connectTimeout;
+ }
+
+ public Integer getMaxParallelRequests() {
+ return maxParallelRequests;
+ }
+
+ public void setMaxParallelRequests(Integer maxParallelRequests) {
+ this.maxParallelRequests = maxParallelRequests;
+ }
+
+ public Integer getMaxRetries() {
+ return maxRetries;
+ }
+
+ public void setMaxRetries(Integer maxRetries) {
+ this.maxRetries = maxRetries;
+ }
+
+ public OpenFgaClient getOpenFgaClient() {
+ return openFgaClient;
+ }
+
+ public void setOpenFgaClient(OpenFgaClient openFgaClient) {
+ this.openFgaClient = openFgaClient;
+ }
+
+ public Long getReadTimeout() {
+ return readTimeout;
+ }
+
+ public void setReadTimeout(Long readTimeout) {
+ this.readTimeout = readTimeout;
+ }
+
+ public Boolean getHealthCheckConsumerEnabled() {
+ return healthCheckConsumerEnabled;
+ }
+
+ public void setHealthCheckConsumerEnabled(Boolean
healthCheckConsumerEnabled) {
+ this.healthCheckConsumerEnabled = healthCheckConsumerEnabled;
+ }
+
+ public Boolean getHealthCheckProducerEnabled() {
+ return healthCheckProducerEnabled;
+ }
+
+ public void setHealthCheckProducerEnabled(Boolean
healthCheckProducerEnabled) {
+ this.healthCheckProducerEnabled = healthCheckProducerEnabled;
+ }
+
+ public String getApiAudience() {
+ return apiAudience;
+ }
+
+ public void setApiAudience(String apiAudience) {
+ this.apiAudience = apiAudience;
+ }
+
+ public String getApiToken() {
+ return apiToken;
+ }
+
+ public void setApiToken(String apiToken) {
+ this.apiToken = apiToken;
+ }
+
+ public String getApiTokenIssuer() {
+ return apiTokenIssuer;
+ }
+
+ public void setApiTokenIssuer(String apiTokenIssuer) {
+ this.apiTokenIssuer = apiTokenIssuer;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getClientSecret() {
+ return clientSecret;
+ }
+
+ public void setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ }
+
+ public Boolean getFailOpen() {
+ return failOpen;
+ }
+
+ public void setFailOpen(Boolean failOpen) {
+ this.failOpen = failOpen;
+ }
+
+ public String getScopes() {
+ return scopes;
+ }
+
+ public void setScopes(String scopes) {
+ this.scopes = scopes;
+ }
+
+ public SSLContextParameters getSslContextParameters() {
+ return sslContextParameters;
+ }
+
+ public void setSslContextParameters(
+ SSLContextParameters sslContextParameters) {
+ this.sslContextParameters = sslContextParameters;
+ }
+
+ public Boolean getUseGlobalSslContextParameters() {
+ return useGlobalSslContextParameters;
+ }
+
+ public void setUseGlobalSslContextParameters(
+ Boolean useGlobalSslContextParameters) {
+ this.useGlobalSslContextParameters = useGlobalSslContextParameters;
+ }
+}
\ No newline at end of file
diff --git
a/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentConverter.java
b/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentConverter.java
new file mode 100644
index 00000000000..98ae6554a26
--- /dev/null
+++
b/components-starter/camel-openfga-starter/src/main/java/org/apache/camel/component/openfga/springboot/OpenFgaComponentConverter.java
@@ -0,0 +1,55 @@
+/*
+ * 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 org.apache.camel.component.openfga.springboot;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.apache.camel.spring.boot.util.BeanReferenceHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import
org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.core.convert.converter.GenericConverter;
+import org.springframework.stereotype.Component;
+
+/**
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Configuration(proxyBeanMethods = false)
+@ConfigurationPropertiesBinding
+@Component
+public class OpenFgaComponentConverter implements GenericConverter {
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ public Set<ConvertiblePair> getConvertibleTypes() {
+ Set<ConvertiblePair> answer = new LinkedHashSet<>();
+ answer.add(new ConvertiblePair(String.class,
org.apache.camel.component.openfga.OpenFgaConfiguration.class));
+ answer.add(new ConvertiblePair(String.class,
dev.openfga.sdk.api.client.OpenFgaClient.class));
+ answer.add(new ConvertiblePair(String.class,
org.apache.camel.support.jsse.SSLContextParameters.class));
+ return answer;
+ }
+
+ public Object convert(
+ Object source,
+ TypeDescriptor sourceType,
+ TypeDescriptor targetType) {
+ return BeanReferenceHelper.resolveBeanReference(applicationContext,
source, targetType, "camel.component.openfga");
+ }
+}
\ No newline at end of file
diff --git
a/components-starter/camel-openfga-starter/src/main/resources/META-INF/LICENSE.txt
b/components-starter/camel-openfga-starter/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 00000000000..6b0b1270ff0
--- /dev/null
+++
b/components-starter/camel-openfga-starter/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
+
diff --git
a/components-starter/camel-openfga-starter/src/main/resources/META-INF/NOTICE.txt
b/components-starter/camel-openfga-starter/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 00000000000..2e215bf2e6b
--- /dev/null
+++
b/components-starter/camel-openfga-starter/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for the Apache Camel distribution. ==
+ =========================================================================
+
+ This product includes software developed by
+ The Apache Software Foundation (http://www.apache.org/).
+
+ Please read the different LICENSE files present in the licenses directory of
+ this distribution.
diff --git
a/components-starter/camel-openfga-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
b/components-starter/camel-openfga-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 00000000000..fe2291e966b
--- /dev/null
+++
b/components-starter/camel-openfga-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,18 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+org.apache.camel.component.openfga.springboot.OpenFgaComponentConverter
+org.apache.camel.component.openfga.springboot.OpenFgaComponentAutoConfiguration
diff --git a/components-starter/pom.xml b/components-starter/pom.xml
index cad14e0a953..7c01ec4cd1b 100644
--- a/components-starter/pom.xml
+++ b/components-starter/pom.xml
@@ -403,6 +403,7 @@
<module>camel-openai-starter</module>
<module>camel-openapi-java-starter</module>
<module>camel-openapi-validator-starter</module>
+ <module>camel-openfga-starter</module>
<module>camel-opensearch-starter</module>
<module>camel-openstack-starter</module>
<module>camel-opentelemetry-metrics-starter</module>
diff --git a/docs/spring-boot/modules/ROOT/nav.adoc
b/docs/spring-boot/modules/ROOT/nav.adoc
index 13c25dbe224..a54292f14bd 100644
--- a/docs/spring-boot/modules/ROOT/nav.adoc
+++ b/docs/spring-boot/modules/ROOT/nav.adoc
@@ -302,6 +302,7 @@
** xref:starters/openai.adoc[LLM]
** xref:starters/openapi-java.adoc[Openapi Java]
** xref:starters/openapi-validator.adoc[Openapi Validator]
+** xref:starters/openfga.adoc[OpenFGA]
** xref:starters/opensearch.adoc[OpenSearch]
** xref:starters/openstack.adoc[OpenStack Cinder]
** xref:starters/opentelemetry-metrics.adoc[OpenTelemetry Metrics]
diff --git a/docs/spring-boot/modules/ROOT/pages/starters/openfga.adoc
b/docs/spring-boot/modules/ROOT/pages/starters/openfga.adoc
new file mode 100644
index 00000000000..f32925ce8e3
--- /dev/null
+++ b/docs/spring-boot/modules/ROOT/pages/starters/openfga.adoc
@@ -0,0 +1,61 @@
+// Do not edit directly!
+// This file was generated by camel-spring-boot-generator-maven-plugin
+= OpenFGA
+:artifactid: camel-openfga-starter
+
+Authorize an Exchange against an OpenFGA relationship graph, and maintain the
relationship tuples it is authorized against.
+
+== What's inside
+
+* xref:{csb-camel-components}::openfga-component.adoc[OpenFGA component], URI
syntax: `openfga:operation`
+
+Please refer to the above links for usage and configuration details.
+
+== Maven coordinates
+
+[source,xml]
+----
+<dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-openfga-starter</artifactId>
+</dependency>
+----
+
+== Spring Boot Auto-Configuration
+
+The starter supports 30 options, which are listed below.
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|===
+| Name | Description | Default | Type
+| camel.component.openfga.api-audience | The audience to request the access
token for in the client-credentials flow. | | String
+| camel.component.openfga.api-token | Pre-shared token sent to OpenFGA in the
Authorization header, for a server started with \{code --authn-method
preshared}. | | String
+| camel.component.openfga.api-token-issuer | The token endpoint the
client-credentials flow exchanges its credentials at. | | String
+| camel.component.openfga.api-url | The base URL of the OpenFGA HTTP API,
without a trailing path. The default assumes OpenFGA running as a sidecar on
its standard HTTP port. | http://localhost:8080 | String
+| camel.component.openfga.authorization-model-id | The identifier of the
authorization model revision to evaluate against. Leave it empty to use
whichever model the store considers latest. Pin it in production. A store keeps
every model it was ever given and latest moves the moment somebody writes a new
one, so an unpinned endpoint can start answering a different question than the
one it was reviewed with - without any change to the route. Pinning also makes
a model rollout a deliberate, [...]
+| camel.component.openfga.autowired-enabled | Whether autowiring is enabled.
This is used for automatic autowiring options (the option must be marked as
autowired) by looking up in the registry to find if there is a single instance
of matching type, which then gets configured on the component. This can be used
for automatic configuring JDBC data sources, JMS connection factories, AWS
Clients, etc. | true | Boolean
+| camel.component.openfga.client-id | Client identifier for the OAuth 2.0
client-credentials flow, for a server that authenticates through an OIDC
provider. Setting it selects that flow, so clientSecret, apiTokenIssuer and
apiAudience are then required too. | | String
+| camel.component.openfga.client-secret | Client secret for the OAuth 2.0
client-credentials flow. | | String
+| camel.component.openfga.configuration | The component configuration. The
option is a org.apache.camel.component.openfga.OpenFgaConfiguration type. | |
OpenFgaConfiguration
+| camel.component.openfga.connect-timeout | How long to wait for the
connection to OpenFGA to be established. The component applies this itself
rather than through the SDK's own connectTimeout setting, which as of
openfga-sdk 0.10.1 is accepted and then never read, leaving the connect phase
bounded only by the operating system. The option is a long type. | 10000 | Long
+| camel.component.openfga.consistency | The consistency the query is answered
with. OpenFGA's default, MINIMIZE_LATENCY, may answer from a replica that has
not caught up yet, which right after a revoke means a tuple that was deleted
can still grant access for a moment. Set HIGHER_CONSISTENCY on the paths where
that window matters, at the cost of latency. Left unset, OpenFGA's own default
applies. | | String
+| camel.component.openfga.enabled | Whether to enable auto configuration of
the openfga component. This is enabled by default. | | Boolean
+| camel.component.openfga.fail-open | Whether to let the exchange proceed when
OpenFGA could not be asked at all, for example because the server is
unreachable. Disabled by default so that an unavailable decision point denies
rather than grants access. Do not enable this in production. It applies to the
check operation and to OpenFgaSecurityPolicy, the two places where proceed has
a meaning, and it covers only a failure to obtain a verdict. An exchange that
was denied, and an exchange th [...]
+| camel.component.openfga.health-check-consumer-enabled | Used for enabling or
disabling all consumer based health checks from this component | true | Boolean
+| camel.component.openfga.health-check-producer-enabled | Used for enabling or
disabling all producer based health checks from this component. Notice: Camel
has by default disabled all producer based health-checks. You can turn on
producer checks globally by setting camel.health.producersEnabled=true. | true
| Boolean
+| camel.component.openfga.lazy-start-producer | Whether the producer should be
started lazy (on the first message). By starting lazy you can use this to allow
CamelContext and routes to startup in situations where a producer may otherwise
fail during starting and cause the route to fail being started. By deferring
this startup to be lazy then the startup failure can be handled during routing
messages via Camel's routing error handlers. Beware that when the first message
is processed then [...]
+| camel.component.openfga.max-parallel-requests | How many of a batchCheck's
checks may be in flight at once. The batch is issued as one request per object,
so this bounds the load one exchange puts on the server. | 10 | Integer
+| camel.component.openfga.max-retries | How many times the SDK retries a
request that failed in a way worth retrying, such as a rate limit or a 5xx. Set
it to 0 to disable retries; the overall wait a routing thread can spend on one
exchange grows with it. | 3 | Integer
+| camel.component.openfga.object | The object being accessed, as an OpenFGA
object identifier such as \{code document:budget}. Evaluated as a Simple
expression against each exchange, so document:$\{header.documentId} names the
resource the message is about. Unlike the subject, taking the object from a
header is normal and safe: the caller is entitled to say which resource it
wants, and the check is what decides whether it may have it. | | String
+| camel.component.openfga.open-fga-client | An existing OpenFgaClient to use.
When set, every option describing how to reach the server - apiUrl, storeId,
the credentials, the timeouts and sslContextParameters - is ignored, because
they are baked into the client that was handed over. The option is a
dev.openfga.sdk.api.client.OpenFgaClient type. | | OpenFgaClient
+| camel.component.openfga.read-timeout | How long to wait for one request to
OpenFGA to complete once connected. A request that times out is a failure to
obtain a verdict rather than a deny, so it fails closed - or proceeds when
failOpen is set. The option is a long type. | 10000 | Long
+| camel.component.openfga.relation | The relation to demand, such as reader or
owner. Evaluated as a Simple expression against each exchange, though a literal
is what you usually want. The relation is the permission being demanded, so
resolving it from an inbound header lets the caller pick the weakest one the
model defines. Keep it literal, or derive it from something the route controls
such as $\{header.CamelHttpMethod}. | | String
+| camel.component.openfga.relations | Comma-separated list of relations the
listRelations operation asks about, for example reader,writer,owner. Only the
ones the subject actually holds come back. | | String
+| camel.component.openfga.scopes | Space-separated scopes to request in the
client-credentials flow. | | String
+| camel.component.openfga.ssl-context-parameters | TLS configuration for the
connection to OpenFGA. Needed to trust a server whose certificate comes from a
private CA, and to present a client certificate to a server that requires
mutual TLS - a SPIFFE X.509-SVID obtained with \{code camel-spiffe}, for
instance, so the workload authenticates to the decision point as itself. The
option is a org.apache.camel.support.jsse.SSLContextParameters type. | |
SSLContextParameters
+| camel.component.openfga.store-id | The identifier of the OpenFGA store
holding the relationship tuples and the authorization model, as returned by
\{code fga store create}. The store is the relationship graph that judges the
exchange, so it comes from the endpoint only and is never taken from a message
header. | | String
+| camel.component.openfga.type | The object type to enumerate for the
listObjects operation, for example document. This is a type name from the
authorization model, so it is taken literally rather than evaluated. | | String
+| camel.component.openfga.use-global-ssl-context-parameters | Enable usage of
global SSL context parameters. | false | Boolean
+| camel.component.openfga.user | The subject to authorize, as an OpenFGA user
identifier such as \{code user:anne}. Evaluated as a Simple expression against
each exchange, so a literal is used as-is and
user:$\{exchangeProperty.CamelKeycloakTokenSubject} resolves whatever an
earlier step established. Read it from an exchange property rather than a
header wherever you can. An exchange property is set by the route itself - by
the step that verified the caller - and nothing outside the rout [...]
+| camel.component.openfga.user-filters | Comma-separated list of user filters
for the listUsers operation, naming which kinds of subject to return. An entry
is either a type, user, or a type and a relation, team#member, to return the
usersets holding the relation rather than the individual subjects. Defaults to
user. | | String
+|===
diff --git a/tooling/camel-spring-boot-bom/pom.xml
b/tooling/camel-spring-boot-bom/pom.xml
index ba99be75808..a9f34e13250 100644
--- a/tooling/camel-spring-boot-bom/pom.xml
+++ b/tooling/camel-spring-boot-bom/pom.xml
@@ -1553,6 +1553,11 @@
<artifactId>camel-openapi-validator-starter</artifactId>
<version>4.23.0-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-openfga-starter</artifactId>
+ <version>4.23.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-opensearch-starter</artifactId>
diff --git a/tooling/camel-spring-boot-dependencies/pom.xml
b/tooling/camel-spring-boot-dependencies/pom.xml
index 98146e9d84e..052279f6262 100644
--- a/tooling/camel-spring-boot-dependencies/pom.xml
+++ b/tooling/camel-spring-boot-dependencies/pom.xml
@@ -1877,6 +1877,11 @@
<artifactId>camel-openapi-validator-starter</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel.springboot</groupId>
+ <artifactId>camel-openfga-starter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-opensearch-starter</artifactId>