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-kamelets.git
The following commit(s) were added to refs/heads/main by this push:
new dd073ecd0 Fix #3014: support all four Salesforce authentication types
(#3059)
dd073ecd0 is described below
commit dd073ecd034a27ddd8146dfb5ef1a4504e1a4060
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Sep 24 11:05:46 2026 +0200
Fix #3014: support all four Salesforce authentication types (#3059)
* Fix #3014: let the Salesforce Kamelets use an authentication type other
than username and password
All six Salesforce Kamelets authenticated with username and password only,
while
camel-salesforce offers four authentication types. This adds the three that
need
nothing but scalar properties.
The obstacle was not the new properties but the old ones: userName and
password
were listed under required in every one of the six, and CLIENT_CREDENTIALS
uses
neither, nor does REFRESH_TOKEN. There is no conditional required in the
JSON
schema these definitions use, so both move out of required and their
placeholders
become optional. Everything else is additive:
authenticationType USERNAME_PASSWORD, CLIENT_CREDENTIALS or REFRESH_TOKEN
refreshToken for REFRESH_TOKEN, marked as a credential
instanceUrl when the authentication response carries none
USERNAME_PASSWORD stays the default, so an existing binding behaves exactly
as
before and keeps working unchanged.
JWT is deliberately absent from the enum. It needs keystore, typed
KeyStoreParameters rather than a scalar, and how to express that is still
open on
the issue. Listing JWT now would advertise a type that cannot authenticate.
This does relax the contract: a binding that omits a username is no longer
rejected, and the schema no longer states that username and password go
together.
That is the price of supporting more than one authentication type here. The
reviewer checklist asks for an upgrade-guide entry on a relaxation; this
repository has no upgrade guide, so the note belongs in the Camel guide
rather
than here.
Verified by driving a message into salesforce-create-sink with
authenticationType=CLIENT_CREDENTIALS and no userName or password. Against
main
the same driver fails with
Route template salesforce-create-sink the following mandatory parameters
must
be provided: userName, password
and against this branch there is no missing parameter error at all; the run
only
stops later, on an unrelated protobuf class in the local JBang environment.
Build
is green with the validator over 262 Kamelets and KameletsCatalogTest
passing.
Authentication against a real Salesforce org is not covered: there are no
Citrus
tests for these Kamelets and CI has no credentials.
Co-Authored-By: Claude Opus 5 <[email protected]>
* Fix #3014: add the JWT authentication type, taking the keystore as a bean
reference
Completes the issue. The previous commit left JWT out because keystore is
typed
KeyStoreParameters rather than a scalar, and how to express that was open.
The catalog already answered it. opensearch-search-source, from #3000, takes
sslContextParameters as an optional string holding a "#bean:name" reference
and
passes it straight through, and no Kamelet in the catalog builds a
KeyStoreParameters or SSLContextParameters bean from scalars today.
Following
that precedent rather than inventing a second idiom for the same family of
JSSE
objects:
keystore "#bean:myKeystore", a registry bean of KeyStoreParameters
jwtAudience audience claim, usually the login URL of the target org
JWT joins the enum now that it can actually authenticate.
The alternative was building the KeyStoreParameters bean inside each
template
from path, password and type. It reads better for the operator, needing no
bean
registration, but Kamelet beans are constructed unconditionally, so every
username and password user would get an empty keystore built as well. Since
the
catalog has no precedent for that and does have one for the reference, the
reference wins.
Not verified: a JWT authentication against a real org, and the binding of
the
keystore reference at runtime. The local probe stops earlier, on a protobuf
class
missing from the JBang environment, before component property binding is
reached.
What is checked here is that all six declare and wire the properties
consistently,
the validator passes over 262 Kamelets and KameletsCatalogTest is green.
Co-Authored-By: Claude Opus 5 <[email protected]>
---------
Co-authored-by: Claude Opus 5 <[email protected]>
---
.../salesforce-composite-upsert-sink.kamelet.yaml | 42 +++++++++++++++++++---
kamelets/salesforce-create-sink.kamelet.yaml | 42 +++++++++++++++++++---
kamelets/salesforce-delete-sink.kamelet.yaml | 42 +++++++++++++++++++---
kamelets/salesforce-pubsub-source.kamelet.yaml | 42 +++++++++++++++++++---
kamelets/salesforce-source.kamelet.yaml | 42 +++++++++++++++++++---
kamelets/salesforce-update-sink.kamelet.yaml | 42 +++++++++++++++++++---
6 files changed, 228 insertions(+), 24 deletions(-)
diff --git a/kamelets/salesforce-composite-upsert-sink.kamelet.yaml
b/kamelets/salesforce-composite-upsert-sink.kamelet.yaml
index 0f1754b29..8e2cd2460 100644
--- a/kamelets/salesforce-composite-upsert-sink.kamelet.yaml
+++ b/kamelets/salesforce-composite-upsert-sink.kamelet.yaml
@@ -37,8 +37,6 @@ spec:
- sObjectIdName
- clientId
- clientSecret
- - userName
- - password
type: object
properties:
sObjectName:
@@ -81,6 +79,37 @@ spec:
format: password
x-descriptors:
- urn:camel:group:credentials
+ authenticationType:
+ title: Authentication Type
+ description: Authentication type to use. USERNAME_PASSWORD needs
userName and password, CLIENT_CREDENTIALS needs only the consumer key and
secret, REFRESH_TOKEN needs refreshToken, JWT needs keystore and jwtAudience.
+ type: string
+ default: USERNAME_PASSWORD
+ enum: ["USERNAME_PASSWORD", "CLIENT_CREDENTIALS", "REFRESH_TOKEN",
"JWT"]
+ refreshToken:
+ title: Refresh Token
+ description: Refresh token used by the REFRESH_TOKEN authentication
type.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ instanceUrl:
+ title: Instance URL
+ description: Salesforce instance URL, needed when the authentication
response does not carry one.
+ type: string
+ example: "https://myinstance.my.salesforce.com"
+ jwtAudience:
+ title: JWT Audience
+ description: Audience claim for the JWT authentication type, usually
the login URL of the target org.
+ type: string
+ example: "https://login.salesforce.com"
+ keystore:
+ title: Keystore
+ description: >-
+ Reference to a registry bean of type
org.apache.camel.support.jsse.KeyStoreParameters,
+ written as "#bean:myBeanName", holding the certificate that signs
the JWT. Required by
+ the JWT authentication type and ignored by the others.
+ type: string
+ example: "#bean:myKeystore"
types:
in:
mediaType: application/json
@@ -99,9 +128,14 @@ spec:
sObjectIdName: "{{sObjectIdName}}"
clientId: "{{clientId}}"
clientSecret: "{{clientSecret}}"
- userName: "{{userName}}"
- password: "{{password}}"
+ authenticationType: "{{authenticationType}}"
+ userName: "{{?userName}}"
+ password: "{{?password}}"
+ refreshToken: "{{?refreshToken}}"
loginUrl: "{{loginUrl}}"
+ instanceUrl: "{{?instanceUrl}}"
+ jwtAudience: "{{?jwtAudience}}"
+ keystore: "{{?keystore}}"
from:
uri: kamelet:source
steps:
diff --git a/kamelets/salesforce-create-sink.kamelet.yaml
b/kamelets/salesforce-create-sink.kamelet.yaml
index ff7f5cc61..87ae92a0d 100644
--- a/kamelets/salesforce-create-sink.kamelet.yaml
+++ b/kamelets/salesforce-create-sink.kamelet.yaml
@@ -34,8 +34,6 @@ spec:
required:
- clientId
- clientSecret
- - userName
- - password
type: object
properties:
sObjectName:
@@ -74,6 +72,37 @@ spec:
format: password
x-descriptors:
- urn:camel:group:credentials
+ authenticationType:
+ title: Authentication Type
+ description: Authentication type to use. USERNAME_PASSWORD needs
userName and password, CLIENT_CREDENTIALS needs only the consumer key and
secret, REFRESH_TOKEN needs refreshToken, JWT needs keystore and jwtAudience.
+ type: string
+ default: USERNAME_PASSWORD
+ enum: ["USERNAME_PASSWORD", "CLIENT_CREDENTIALS", "REFRESH_TOKEN",
"JWT"]
+ refreshToken:
+ title: Refresh Token
+ description: Refresh token used by the REFRESH_TOKEN authentication
type.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ instanceUrl:
+ title: Instance URL
+ description: Salesforce instance URL, needed when the authentication
response does not carry one.
+ type: string
+ example: "https://myinstance.my.salesforce.com"
+ jwtAudience:
+ title: JWT Audience
+ description: Audience claim for the JWT authentication type, usually
the login URL of the target org.
+ type: string
+ example: "https://login.salesforce.com"
+ keystore:
+ title: Keystore
+ description: >-
+ Reference to a registry bean of type
org.apache.camel.support.jsse.KeyStoreParameters,
+ written as "#bean:myBeanName", holding the certificate that signs
the JWT. Required by
+ the JWT authentication type and ignored by the others.
+ type: string
+ example: "#bean:myKeystore"
types:
in:
mediaType: application/json
@@ -87,9 +116,14 @@ spec:
properties:
clientId: "{{clientId}}"
clientSecret: "{{clientSecret}}"
- userName: "{{userName}}"
- password: "{{password}}"
+ authenticationType: "{{authenticationType}}"
+ userName: "{{?userName}}"
+ password: "{{?password}}"
+ refreshToken: "{{?refreshToken}}"
loginUrl: "{{loginUrl}}"
+ instanceUrl: "{{?instanceUrl}}"
+ jwtAudience: "{{?jwtAudience}}"
+ keystore: "{{?keystore}}"
from:
uri: kamelet:source
steps:
diff --git a/kamelets/salesforce-delete-sink.kamelet.yaml
b/kamelets/salesforce-delete-sink.kamelet.yaml
index b6b9b23e1..4fb7171e5 100644
--- a/kamelets/salesforce-delete-sink.kamelet.yaml
+++ b/kamelets/salesforce-delete-sink.kamelet.yaml
@@ -34,8 +34,6 @@ spec:
required:
- clientId
- clientSecret
- - userName
- - password
type: object
properties:
loginUrl:
@@ -69,6 +67,37 @@ spec:
format: password
x-descriptors:
- urn:camel:group:credentials
+ authenticationType:
+ title: Authentication Type
+ description: Authentication type to use. USERNAME_PASSWORD needs
userName and password, CLIENT_CREDENTIALS needs only the consumer key and
secret, REFRESH_TOKEN needs refreshToken, JWT needs keystore and jwtAudience.
+ type: string
+ default: USERNAME_PASSWORD
+ enum: ["USERNAME_PASSWORD", "CLIENT_CREDENTIALS", "REFRESH_TOKEN",
"JWT"]
+ refreshToken:
+ title: Refresh Token
+ description: Refresh token used by the REFRESH_TOKEN authentication
type.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ instanceUrl:
+ title: Instance URL
+ description: Salesforce instance URL, needed when the authentication
response does not carry one.
+ type: string
+ example: "https://myinstance.my.salesforce.com"
+ jwtAudience:
+ title: JWT Audience
+ description: Audience claim for the JWT authentication type, usually
the login URL of the target org.
+ type: string
+ example: "https://login.salesforce.com"
+ keystore:
+ title: Keystore
+ description: >-
+ Reference to a registry bean of type
org.apache.camel.support.jsse.KeyStoreParameters,
+ written as "#bean:myBeanName", holding the certificate that signs
the JWT. Required by
+ the JWT authentication type and ignored by the others.
+ type: string
+ example: "#bean:myKeystore"
types:
in:
mediaType: application/json
@@ -92,9 +121,14 @@ spec:
properties:
clientId: "{{clientId}}"
clientSecret: "{{clientSecret}}"
- userName: "{{userName}}"
- password: "{{password}}"
+ authenticationType: "{{authenticationType}}"
+ userName: "{{?userName}}"
+ password: "{{?password}}"
+ refreshToken: "{{?refreshToken}}"
loginUrl: "{{loginUrl}}"
+ instanceUrl: "{{?instanceUrl}}"
+ jwtAudience: "{{?jwtAudience}}"
+ keystore: "{{?keystore}}"
from:
uri: kamelet:source
steps:
diff --git a/kamelets/salesforce-pubsub-source.kamelet.yaml
b/kamelets/salesforce-pubsub-source.kamelet.yaml
index fccd1c007..1d417ff82 100644
--- a/kamelets/salesforce-pubsub-source.kamelet.yaml
+++ b/kamelets/salesforce-pubsub-source.kamelet.yaml
@@ -35,8 +35,6 @@ spec:
- topic
- clientId
- clientSecret
- - userName
- - password
type: object
properties:
topic:
@@ -75,6 +73,37 @@ spec:
format: password
x-descriptors:
- urn:camel:group:credentials
+ authenticationType:
+ title: Authentication Type
+ description: Authentication type to use. USERNAME_PASSWORD needs
userName and password, CLIENT_CREDENTIALS needs only the consumer key and
secret, REFRESH_TOKEN needs refreshToken, JWT needs keystore and jwtAudience.
+ type: string
+ default: USERNAME_PASSWORD
+ enum: ["USERNAME_PASSWORD", "CLIENT_CREDENTIALS", "REFRESH_TOKEN",
"JWT"]
+ refreshToken:
+ title: Refresh Token
+ description: Refresh token used by the REFRESH_TOKEN authentication
type.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ instanceUrl:
+ title: Instance URL
+ description: Salesforce instance URL, needed when the authentication
response does not carry one.
+ type: string
+ example: "https://myinstance.my.salesforce.com"
+ jwtAudience:
+ title: JWT Audience
+ description: Audience claim for the JWT authentication type, usually
the login URL of the target org.
+ type: string
+ example: "https://login.salesforce.com"
+ keystore:
+ title: Keystore
+ description: >-
+ Reference to a registry bean of type
org.apache.camel.support.jsse.KeyStoreParameters,
+ written as "#bean:myBeanName", holding the certificate that signs
the JWT. Required by
+ the JWT authentication type and ignored by the others.
+ type: string
+ example: "#bean:myKeystore"
deserializeType:
title: Deserialize Type
description: >-
@@ -114,9 +143,14 @@ spec:
properties:
clientId: "{{clientId}}"
clientSecret: "{{clientSecret}}"
- userName: "{{userName}}"
- password: "{{password}}"
+ authenticationType: "{{authenticationType}}"
+ userName: "{{?userName}}"
+ password: "{{?password}}"
+ refreshToken: "{{?refreshToken}}"
loginUrl: "{{loginUrl}}"
+ instanceUrl: "{{?instanceUrl}}"
+ jwtAudience: "{{?jwtAudience}}"
+ keystore: "{{?keystore}}"
from:
uri: "{{local-salesforce-pubsub}}:pubSubSubscribe:{{topic}}"
parameters:
diff --git a/kamelets/salesforce-source.kamelet.yaml
b/kamelets/salesforce-source.kamelet.yaml
index b33677bb9..37a59b6f6 100644
--- a/kamelets/salesforce-source.kamelet.yaml
+++ b/kamelets/salesforce-source.kamelet.yaml
@@ -36,8 +36,6 @@ spec:
- topicName
- clientId
- clientSecret
- - userName
- - password
type: object
properties:
query:
@@ -87,6 +85,37 @@ spec:
format: password
x-descriptors:
- urn:camel:group:credentials
+ authenticationType:
+ title: Authentication Type
+ description: Authentication type to use. USERNAME_PASSWORD needs
userName and password, CLIENT_CREDENTIALS needs only the consumer key and
secret, REFRESH_TOKEN needs refreshToken, JWT needs keystore and jwtAudience.
+ type: string
+ default: USERNAME_PASSWORD
+ enum: ["USERNAME_PASSWORD", "CLIENT_CREDENTIALS", "REFRESH_TOKEN",
"JWT"]
+ refreshToken:
+ title: Refresh Token
+ description: Refresh token used by the REFRESH_TOKEN authentication
type.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ instanceUrl:
+ title: Instance URL
+ description: Salesforce instance URL, needed when the authentication
response does not carry one.
+ type: string
+ example: "https://myinstance.my.salesforce.com"
+ jwtAudience:
+ title: JWT Audience
+ description: Audience claim for the JWT authentication type, usually
the login URL of the target org.
+ type: string
+ example: "https://login.salesforce.com"
+ keystore:
+ title: Keystore
+ description: >-
+ Reference to a registry bean of type
org.apache.camel.support.jsse.KeyStoreParameters,
+ written as "#bean:myBeanName", holding the certificate that signs
the JWT. Required by
+ the JWT authentication type and ignored by the others.
+ type: string
+ example: "#bean:myKeystore"
notifyForOperationCreate:
title: Notify Operation Create
description: Notify for create operation.
@@ -135,9 +164,14 @@ spec:
properties:
clientId: "{{clientId}}"
clientSecret: "{{clientSecret}}"
- userName: "{{userName}}"
- password: "{{password}}"
+ authenticationType: "{{authenticationType}}"
+ userName: "{{?userName}}"
+ password: "{{?password}}"
+ refreshToken: "{{?refreshToken}}"
loginUrl: "{{loginUrl}}"
+ instanceUrl: "{{?instanceUrl}}"
+ jwtAudience: "{{?jwtAudience}}"
+ keystore: "{{?keystore}}"
from:
uri: "{{local-salesforce}}:{{operation}}:{{topicName}}"
parameters:
diff --git a/kamelets/salesforce-update-sink.kamelet.yaml
b/kamelets/salesforce-update-sink.kamelet.yaml
index 776d857ef..4e70b330c 100644
--- a/kamelets/salesforce-update-sink.kamelet.yaml
+++ b/kamelets/salesforce-update-sink.kamelet.yaml
@@ -35,8 +35,6 @@ spec:
required:
- clientId
- clientSecret
- - userName
- - password
type: object
properties:
loginUrl:
@@ -70,6 +68,37 @@ spec:
format: password
x-descriptors:
- urn:camel:group:credentials
+ authenticationType:
+ title: Authentication Type
+ description: Authentication type to use. USERNAME_PASSWORD needs
userName and password, CLIENT_CREDENTIALS needs only the consumer key and
secret, REFRESH_TOKEN needs refreshToken, JWT needs keystore and jwtAudience.
+ type: string
+ default: USERNAME_PASSWORD
+ enum: ["USERNAME_PASSWORD", "CLIENT_CREDENTIALS", "REFRESH_TOKEN",
"JWT"]
+ refreshToken:
+ title: Refresh Token
+ description: Refresh token used by the REFRESH_TOKEN authentication
type.
+ type: string
+ format: password
+ x-descriptors:
+ - urn:camel:group:credentials
+ instanceUrl:
+ title: Instance URL
+ description: Salesforce instance URL, needed when the authentication
response does not carry one.
+ type: string
+ example: "https://myinstance.my.salesforce.com"
+ jwtAudience:
+ title: JWT Audience
+ description: Audience claim for the JWT authentication type, usually
the login URL of the target org.
+ type: string
+ example: "https://login.salesforce.com"
+ keystore:
+ title: Keystore
+ description: >-
+ Reference to a registry bean of type
org.apache.camel.support.jsse.KeyStoreParameters,
+ written as "#bean:myBeanName", holding the certificate that signs
the JWT. Required by
+ the JWT authentication type and ignored by the others.
+ type: string
+ example: "#bean:myKeystore"
types:
in:
mediaType: application/json
@@ -86,9 +115,14 @@ spec:
properties:
clientId: "{{clientId}}"
clientSecret: "{{clientSecret}}"
- userName: "{{userName}}"
- password: "{{password}}"
+ authenticationType: "{{authenticationType}}"
+ userName: "{{?userName}}"
+ password: "{{?password}}"
+ refreshToken: "{{?refreshToken}}"
loginUrl: "{{loginUrl}}"
+ instanceUrl: "{{?instanceUrl}}"
+ jwtAudience: "{{?jwtAudience}}"
+ keystore: "{{?keystore}}"
from:
uri: kamelet:source
steps: