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:

Reply via email to