You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2026/09/24 09:05:54 UTC
(camel-kamelets) branch main updated: Fix #3014: support all four Salesforce authentication types (#3059)
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 <an...@gmail.com>
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 <no...@anthropic.com>
* 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 <no...@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <no...@anthropic.com>
---
.../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: