Repository: camel
Updated Branches:
  refs/heads/master 7c1045283 -> d4c9a3da4


CAMEL-11013 Support OAuth 2.0 JWT Bearer Token ...

...Flow

This gives the users ability to use OAuth 2.0 JWT Bearer Token Flow[1]
to gain access tokens from Salesforce using JWT token signed by a
certificate defined on the Salesforce connected application.

[1] https://help.salesforce.com/articleView?id=remoteaccess_oauth_jwt_flow.htm


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/032047c3
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/032047c3
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/032047c3

Branch: refs/heads/master
Commit: 032047c3df3df1d6db52b28f56f41daa5733c5bb
Parents: 7c10452
Author: Zoran Regvart <zregv...@apache.org>
Authored: Wed Mar 15 12:51:55 2017 +0100
Committer: Zoran Regvart <zregv...@apache.org>
Committed: Wed Mar 15 13:02:08 2017 +0100

----------------------------------------------------------------------
 .../src/main/docs/salesforce-component.adoc     |   3 +-
 .../salesforce/SalesforceComponent.java         |  47 +++--
 .../salesforce/SalesforceComponentVerifier.java |   2 +-
 .../salesforce/SalesforceLoginConfig.java       |  99 +++++++--
 .../salesforce/internal/SalesforceSession.java  | 131 +++++++++---
 .../component/salesforce/LoginConfigHelper.java | 105 +++++-----
 ...sforceJwtBearerTokenFlowIntegrationTest.java |  56 +++++
 .../internal/SalesforceSessionTest.java         |  54 +++++
 .../internal/SessionIntegrationTest.java        |   3 +-
 .../src/test/resources/test.p12                 | Bin 0 -> 2416 bytes
 .../apache/camel/maven/CamelSalesforceMojo.java |   3 +-
 ...CamelSalesforceIntegrationTests.connectedApp |   1 +
 .../SalesforceComponentConfiguration.java       | 208 +++++++++++--------
 13 files changed, 499 insertions(+), 213 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
 
b/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
index c99a68b..28d6567 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/docs/salesforce-component.adoc
@@ -427,7 +427,7 @@ link:salesforce.html[Salesforce].
 
 
 // component options: START
-The Salesforce component supports 24 options which are listed below.
+The Salesforce component supports 25 options which are listed below.
 
 
 
@@ -438,6 +438,7 @@ The Salesforce component supports 24 options which are 
listed below.
 | loginUrl | security | https://login.salesforce.com | String | Salesforce 
login URL defaults to https://login.salesforce.com
 | clientId | security |  | String | Salesforce connected application Consumer 
Key
 | clientSecret | security |  | String | Salesforce connected application 
Consumer Secret
+| keystore | security |  | KeyStoreParameters | KeyStoreParameters to use in 
OAuth 2.0 JWT Bearer Token Flow.
 | refreshToken | security |  | String | Salesforce connected application 
Consumer token
 | userName | security |  | String | Salesforce account user name
 | password | security |  | String | Salesforce account password

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
index 9696207..80fdf8a 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponent.java
@@ -46,6 +46,7 @@ import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.ReflectionHelper;
 import org.apache.camel.util.ServiceHelper;
+import org.apache.camel.util.jsse.KeyStoreParameters;
 import org.apache.camel.util.jsse.SSLContextParameters;
 import org.eclipse.jetty.client.HttpProxy;
 import org.eclipse.jetty.client.Origin;
@@ -88,6 +89,8 @@ public class SalesforceComponent extends UriEndpointComponent 
implements Endpoin
     private String userName;
     @Metadata(label = "security", secret = true)
     private String password;
+    @Metadata(label = "security", secret = true)
+    private KeyStoreParameters keystore;
     @Metadata(label = "security")
     private boolean lazyLogin;
 
@@ -220,26 +223,18 @@ public class SalesforceComponent extends 
UriEndpointComponent implements Endpoin
     @Override
     protected void doStart() throws Exception {
         if (loginConfig == null) {
-            loginConfig = new SalesforceLoginConfig();
-            if (loginUrl != null) {
-                loginConfig.setLoginUrl(loginUrl);
-            }
-            if (refreshToken != null) {
-                loginConfig.setRefreshToken(refreshToken);
-            }
-            if (clientId != null) {
-                loginConfig.setClientId(clientId);
-            }
-            if (clientSecret != null) {
-                loginConfig.setClientSecret(clientSecret);
-            }
-            if (userName != null) {
-                loginConfig.setUserName(userName);
-            }
-            if (password != null) {
-                loginConfig.setPassword(password);
+            if (ObjectHelper.isNotEmpty(password)) {
+                loginConfig = new SalesforceLoginConfig(loginUrl, clientId, 
clientSecret, userName, password, lazyLogin);
+            } else if (ObjectHelper.isNotEmpty(refreshToken)) {
+                loginConfig = new SalesforceLoginConfig(loginUrl, clientId, 
clientSecret, refreshToken, lazyLogin);
+            } else if (ObjectHelper.isNotEmpty(keystore)) {
+                loginConfig = new SalesforceLoginConfig(loginUrl, clientId, 
userName, keystore, lazyLogin);
+            } else {
+                throw new IllegalArgumentException("Cannot define a login 
configuration, the component configuration"
+                    + " does not contain `password`, `refreshToken` or 
`keystore` parameters. Specifying one of those"
+                    + " determines the type of authentication performed.");
             }
-            loginConfig.setLazyLogin(lazyLogin);
+
             LOG.debug("Created login configuration: {}", loginConfig);
         } else {
             LOG.debug("Using shared login configuration: {}", loginConfig);
@@ -303,7 +298,7 @@ public class SalesforceComponent extends 
UriEndpointComponent implements Endpoin
 
         // support restarts
         if (this.session == null) {
-            this.session = new SalesforceSession(httpClient, 
httpClient.getTimeout(), loginConfig);
+            this.session = new SalesforceSession(getCamelContext(), 
httpClient, httpClient.getTimeout(), loginConfig);
         }
         // set session before calling start()
         httpClient.setSession(this.session);
@@ -470,6 +465,7 @@ public class SalesforceComponent extends 
UriEndpointComponent implements Endpoin
 
     public String getClientSecret() {
         return clientSecret;
+
     }
 
     /**
@@ -479,6 +475,17 @@ public class SalesforceComponent extends 
UriEndpointComponent implements Endpoin
         this.clientSecret = clientSecret;
     }
 
+    /**
+     * {@link KeyStoreParameters} to use in OAuth 2.0 JWT Bearer Token Flow.
+     */
+    public void setKeystore(final KeyStoreParameters keystore) {
+        this.keystore = keystore;
+    }
+
+    public KeyStoreParameters getKeystore() {
+        return keystore;
+    }
+
     public String getRefreshToken() {
         return refreshToken;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponentVerifier.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponentVerifier.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponentVerifier.java
index f7ce00a..7d6df25 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponentVerifier.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceComponentVerifier.java
@@ -90,7 +90,7 @@ public class SalesforceComponentVerifier extends 
DefaultComponentVerifier {
             
httpClient.setConnectTimeout(SalesforceComponent.CONNECTION_TIMEOUT);
             configureHttpProxy(httpClient, parameters);
 
-            SalesforceSession session = new SalesforceSession(httpClient, 
httpClient.getTimeout(), loginConfig);
+            SalesforceSession session = new 
SalesforceSession(getCamelContext(), httpClient, httpClient.getTimeout(), 
loginConfig);
             DefaultRestClient client = new DefaultRestClient(httpClient, 
configuration.getApiVersion(), configuration.getFormat(), session);
 
             httpClient.setSession(session);

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
index 14dc0ed..d703d9f 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/SalesforceLoginConfig.java
@@ -16,13 +16,21 @@
  */
 package org.apache.camel.component.salesforce;
 
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.jsse.KeyStoreParameters;
+
 /**
  * Configuration object for Salesforce login properties
  */
 public class SalesforceLoginConfig {
 
+    public enum Type {
+        USERNAME_PASSWORD, REFRESH_TOKEN, JWT
+    }
+
     public static final String DEFAULT_LOGIN_URL = 
"https://login.salesforce.com";;
 
+    private Type type;
     private String loginUrl;
     private String clientId;
     private String clientSecret;
@@ -33,30 +41,38 @@ public class SalesforceLoginConfig {
     // note that login issues may not surface until a message needs to be 
processed
     private boolean lazyLogin;
 
+    private KeyStoreParameters keystore;
+
     public SalesforceLoginConfig() {
         loginUrl = DEFAULT_LOGIN_URL;
         lazyLogin = false;
     }
 
-    public SalesforceLoginConfig(String loginUrl,
-                                 String clientId, String clientSecret,
-                                 String userName, String password, boolean 
lazyLogin) {
+    private SalesforceLoginConfig(Type type, String loginUrl, String clientId, 
String clientSecret, String refreshToken,
+        String userName, String password, boolean lazyLogin, 
KeyStoreParameters keystore) {
+        this.type = type;
         this.loginUrl = loginUrl;
         this.clientId = clientId;
         this.clientSecret = clientSecret;
+        this.refreshToken = refreshToken;
         this.userName = userName;
         this.password = password;
         this.lazyLogin = lazyLogin;
+        this.keystore = keystore;
     }
 
-    public SalesforceLoginConfig(String loginUrl,
-            String clientId, String clientSecret,
-            String refreshToken, boolean lazyLogin) {
-        this.loginUrl = loginUrl;
-        this.clientId = clientId;
-        this.clientSecret = clientSecret;
-        this.refreshToken = refreshToken;
-        this.lazyLogin = lazyLogin;
+    public SalesforceLoginConfig(String loginUrl, String clientId, String 
clientSecret, String userName,
+        String password, boolean lazyLogin) {
+        this(Type.USERNAME_PASSWORD, loginUrl, clientId, clientSecret, null, 
userName, password, lazyLogin, null);
+    }
+
+    public SalesforceLoginConfig(String loginUrl, String clientId, String 
clientSecret, String refreshToken,
+        boolean lazyLogin) {
+        this(Type.REFRESH_TOKEN, loginUrl, clientId, clientSecret, 
refreshToken, null, null, lazyLogin, null);
+    }
+
+    public SalesforceLoginConfig(String loginUrl, String clientId, String 
userName, KeyStoreParameters keystore, boolean lazyLogin) {
+        this(Type.JWT, loginUrl, clientId, null, null, userName, null, 
lazyLogin, keystore);
     }
 
     public String getLoginUrl() {
@@ -92,6 +108,18 @@ public class SalesforceLoginConfig {
         this.clientSecret = clientSecret;
     }
 
+    /**
+     * Keystore parameters for keystore containing certificate and private key 
needed for OAuth 2.0 JWT Bearer Token
+     * Flow.
+     */
+    public void setKeystore(final KeyStoreParameters keystore) {
+        this.keystore = keystore;
+        this.type = Type.JWT;
+    }
+
+    public KeyStoreParameters getKeystore() {
+        return keystore;
+    }
 
     public String getRefreshToken() {
         return refreshToken;
@@ -102,6 +130,11 @@ public class SalesforceLoginConfig {
      */
     public void setRefreshToken(String refreshToken) {
         this.refreshToken = refreshToken;
+        this.type = Type.REFRESH_TOKEN;
+    }
+
+    public Type getType() {
+        return type;
     }
 
     public String getUserName() {
@@ -124,6 +157,7 @@ public class SalesforceLoginConfig {
      */
     public void setPassword(String password) {
         this.password = password;
+        this.type = Type.USERNAME_PASSWORD;
     }
 
     public boolean isLazyLogin() {
@@ -131,21 +165,46 @@ public class SalesforceLoginConfig {
     }
 
     /**
-     * Flag to enable/disable lazy OAuth, default is false. When enabled, 
OAuth token retrieval or generation is not done until the first API call
+     * Flag to enable/disable lazy OAuth, default is false. When enabled, 
OAuth token retrieval or generation is not
+     * done until the first API call
      */
     public void setLazyLogin(boolean lazyLogin) {
         this.lazyLogin = lazyLogin;
     }
 
+    public void validate() {
+        ObjectHelper.notNull(loginUrl, "loginUrl");
+        ObjectHelper.notNull(clientId, "clientId");
+
+        final boolean hasRefreshToken = ObjectHelper.isEmpty(refreshToken);
+
+        if (hasRefreshToken && keystore == null) {
+            ObjectHelper.notNull(userName, "userName (username/password 
authentication)");
+            ObjectHelper.notNull(password, "password (username/password 
authentication)");
+            ObjectHelper.notNull(clientSecret, "clientSecret 
(username/password authentication)");
+            type = Type.USERNAME_PASSWORD;
+        } else if (hasRefreshToken && keystore == null) {
+            ObjectHelper.notNull(refreshToken, "refreshToken (authentication 
with refresh token)");
+            ObjectHelper.notNull(clientSecret, "clientSecret (authentication 
with refresh token)");
+            type = Type.REFRESH_TOKEN;
+        } else if (keystore != null) {
+            ObjectHelper.notNull(userName, "userName (JWT authentication)");
+            ObjectHelper.notNull(keystore, "keystore (JWT authentication)");
+            type = Type.JWT;
+        } else {
+            throw new IllegalArgumentException(
+                "You must specify parameters aligned with one of the supported 
authentication methods:"
+                    + " for username and password authentication: userName, 
password, clientSecret;"
+                    + " for refresh token authentication: refreshToken, 
clientSecret;"
+                    + " for JWT: userName, keystore. And for every one of 
those loginUrl and clientId must be specified also.");
+        }
+    }
+
     @Override
     public String toString() {
-        return "SalesforceLoginConfig["
-            + "loginUrl='" + loginUrl + '\''
-            + ", clientId='" + clientId + '\''
-            + ", clientSecret='********'"
-            + ", refreshToken='" + refreshToken + '\''
-            + ", userName='" + userName + '\''
-            + ", password=********'" + password + '\''
-            + ", lazyLogin=" + lazyLogin + ']';
+        return "SalesforceLoginConfig[" + "loginUrl='" + loginUrl + '\'' + ", 
clientId='" + clientId + '\''
+            + ", clientSecret='********'" + ", refreshToken='" + refreshToken 
+ '\'' + ", userName='" + userName + '\''
+            + ", password=********'" + password + '\'' + ", 
keystore=********'" + keystore + '\'' + ", lazyLogin="
+            + lazyLogin + ']';
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
index f3047f7..33d8ddf 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/main/java/org/apache/camel/component/salesforce/internal/SalesforceSession.java
@@ -18,7 +18,15 @@ package org.apache.camel.component.salesforce.internal;
 
 import java.io.IOException;
 import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.time.Clock;
 import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Enumeration;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArraySet;
@@ -28,15 +36,18 @@ import java.util.concurrent.TimeoutException;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
+import org.apache.camel.CamelContext;
 import org.apache.camel.Service;
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
 import org.apache.camel.component.salesforce.SalesforceLoginConfig;
+import org.apache.camel.component.salesforce.SalesforceLoginConfig.Type;
 import org.apache.camel.component.salesforce.api.SalesforceException;
 import org.apache.camel.component.salesforce.api.dto.RestError;
 import org.apache.camel.component.salesforce.api.utils.JsonUtils;
 import org.apache.camel.component.salesforce.internal.dto.LoginError;
 import org.apache.camel.component.salesforce.internal.dto.LoginToken;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.jsse.KeyStoreParameters;
 import org.eclipse.jetty.client.HttpConversation;
 import org.eclipse.jetty.client.api.ContentResponse;
 import org.eclipse.jetty.client.api.Request;
@@ -49,6 +60,13 @@ import org.slf4j.LoggerFactory;
 
 public class SalesforceSession implements Service {
 
+    private static final String JWT_SIGNATURE_ALGORITHM = "SHA256withRSA";
+
+    private static final int JWT_CLAIM_WINDOW = 270; // 4.5 min
+
+    private static final String JWT_HEADER = Base64.getUrlEncoder()
+        
.encodeToString("{\"alg\":\"RS256\"}".getBytes(StandardCharsets.UTF_8));
+
     private static final String OAUTH2_REVOKE_PATH = 
"/services/oauth2/revoke?token=";
     private static final String OAUTH2_TOKEN_PATH = "/services/oauth2/token";
 
@@ -65,20 +83,14 @@ public class SalesforceSession implements Service {
     private volatile String accessToken;
     private volatile String instanceUrl;
 
-    public SalesforceSession(SalesforceHttpClient httpClient, long timeout, 
SalesforceLoginConfig config) {
+    private CamelContext camelContext;
+
+    public SalesforceSession(CamelContext camelContext, SalesforceHttpClient 
httpClient, long timeout, SalesforceLoginConfig config) {
+        this.camelContext = camelContext;
         // validate parameters
         ObjectHelper.notNull(httpClient, "httpClient");
         ObjectHelper.notNull(config, "SalesforceLoginConfig");
-        ObjectHelper.notNull(config.getLoginUrl(), "loginUrl");
-        ObjectHelper.notNull(config.getClientId(), "clientId");
-        ObjectHelper.notNull(config.getClientSecret(), "clientSecret");
-
-        if (ObjectHelper.isEmpty(config.getRefreshToken())) {
-            ObjectHelper.notNull(config.getUserName(), "userName");
-            ObjectHelper.notNull(config.getPassword(), "password");
-        } else {
-            ObjectHelper.notNull(config.getRefreshToken(), "refreshToken");
-        }
+        config.validate();
 
         this.httpClient = httpClient;
         this.timeout = timeout;
@@ -129,7 +141,9 @@ public class SalesforceSession implements Service {
     }
 
     /**
-     * Creates login request, allows SalesforceSecurityHandler to create a 
login request for a failed authentication conversation
+     * Creates login request, allows SalesforceSecurityHandler to create a 
login request for a failed authentication
+     * conversation
+     * 
      * @return login POST request.
      */
     public Request getLoginRequest(HttpConversation conversation) {
@@ -138,34 +152,90 @@ public class SalesforceSession implements Service {
         final Fields fields = new Fields(true);
 
         fields.put("client_id", config.getClientId());
-        fields.put("client_secret", config.getClientSecret());
         fields.put("format", "json");
 
-        if (ObjectHelper.isEmpty(config.getRefreshToken())) {
+        final Type type = config.getType();
+        switch (type) {
+        case USERNAME_PASSWORD:
+            fields.put("client_secret", config.getClientSecret());
             fields.put("grant_type", "password");
             fields.put("username", config.getUserName());
             fields.put("password", config.getPassword());
-        } else {
+            break;
+        case REFRESH_TOKEN:
+            fields.put("client_secret", config.getClientSecret());
             fields.put("grant_type", "refresh_token");
             fields.put("refresh_token", config.getRefreshToken());
+            break;
+        case JWT:
+            fields.put("grant_type", 
"urn:ietf:params:oauth:grant-type:jwt-bearer");
+            fields.put("assertion", generateJwtAssertion());
+            break;
+        default:
+            throw new IllegalArgumentException("Unsupported login 
configuration type: " + type);
         }
 
         final Request post;
         if (conversation == null) {
             post = httpClient.POST(loginUrl);
         } else {
-            post = httpClient.newHttpRequest(conversation, 
URI.create(loginUrl))
-                .method(HttpMethod.POST);
+            post = httpClient.newHttpRequest(conversation, 
URI.create(loginUrl)).method(HttpMethod.POST);
+        }
+
+        return post.content(new FormContentProvider(fields)).timeout(timeout, 
TimeUnit.MILLISECONDS);
+    }
+
+    String generateJwtAssertion() {
+        final long utcPlusWindow = Clock.systemUTC().millis() / 1000 + 
JWT_CLAIM_WINDOW;
+
+        final StringBuilder claim = new 
StringBuilder().append("{\"iss\":\"").append(config.getClientId())
+            
.append("\",\"sub\":\"").append(config.getUserName()).append("\",\"aud\":\"").append(config.getLoginUrl())
+            .append("\",\"exp\":\"").append(utcPlusWindow).append("\"}");
+
+        final StringBuilder token = new StringBuilder(JWT_HEADER).append('.')
+            
.append(Base64.getUrlEncoder().encodeToString(claim.toString().getBytes(StandardCharsets.UTF_8)));
+
+        final KeyStoreParameters keyStoreParameters = config.getKeystore();
+        keyStoreParameters.setCamelContext(camelContext);
+
+        try {
+            final KeyStore keystore = keyStoreParameters.createKeyStore();
+
+            final Enumeration<String> aliases = keystore.aliases();
+            String alias = null;
+            while (aliases.hasMoreElements()) {
+                String tmp = aliases.nextElement();
+                if (keystore.isKeyEntry(tmp)) {
+                    if (alias == null) {
+                        alias = tmp;
+                    } else {
+                        throw new IllegalArgumentException("The given keystore 
`" + keyStoreParameters.getResource()
+                            + "` contains more than one key entry, expecting 
only one");
+                    }
+                }
+            }
+
+            PrivateKey key = (PrivateKey) keystore.getKey(alias, 
keyStoreParameters.getPassword().toCharArray());
+
+            Signature signature = 
Signature.getInstance(JWT_SIGNATURE_ALGORITHM);
+            signature.initSign(key);
+            
signature.update(token.toString().getBytes(StandardCharsets.UTF_8));
+            byte[] signed = signature.sign();
+
+            
token.append('.').append(Base64.getUrlEncoder().encodeToString(signed));
+        } catch (IOException | GeneralSecurityException e) {
+            throw new IllegalStateException(e);
         }
 
-        return post.content(new FormContentProvider(fields))
-            .timeout(timeout, TimeUnit.MILLISECONDS);
+        return token.toString();
     }
 
     /**
-     * Parses login response, allows SalesforceSecurityHandler to parse a 
login request for a failed authentication conversation.
+     * Parses login response, allows SalesforceSecurityHandler to parse a 
login request for a failed authentication
+     * conversation.
      */
-    public synchronized void parseLoginResponse(ContentResponse loginResponse, 
String responseContent) throws SalesforceException {
+    public synchronized void parseLoginResponse(ContentResponse loginResponse, 
String responseContent)
+        throws SalesforceException {
         final int responseStatus = loginResponse.getStatus();
 
         try {
@@ -193,15 +263,16 @@ public class SalesforceSession implements Service {
             case HttpStatus.BAD_REQUEST_400:
                 // parse the response to get error
                 final LoginError error = 
objectMapper.readValue(responseContent, LoginError.class);
-                final String msg = String.format("Login error code:[%s] 
description:[%s]",
-                    error.getError(), error.getErrorDescription());
+                final String msg = String.format("Login error code:[%s] 
description:[%s]", error.getError(),
+                    error.getErrorDescription());
                 final List<RestError> errors = new ArrayList<RestError>();
                 errors.add(new RestError(msg, error.getErrorDescription()));
                 throw new SalesforceException(errors, 
HttpStatus.BAD_REQUEST_400);
 
             default:
-                throw new SalesforceException(String.format("Login error 
status:[%s] reason:[%s]",
-                    responseStatus, loginResponse.getReason()), 
responseStatus);
+                throw new SalesforceException(
+                    String.format("Login error status:[%s] reason:[%s]", 
responseStatus, loginResponse.getReason()),
+                    responseStatus);
             }
         } catch (IOException e) {
             String msg = "Login error: response parse exception " + 
e.getMessage();
@@ -215,9 +286,9 @@ public class SalesforceSession implements Service {
         }
 
         try {
-            String logoutUrl = (instanceUrl == null ? config.getLoginUrl() : 
instanceUrl) + OAUTH2_REVOKE_PATH + accessToken;
-            final Request logoutGet = httpClient.newRequest(logoutUrl)
-                .timeout(timeout, TimeUnit.MILLISECONDS);
+            String logoutUrl = (instanceUrl == null ? config.getLoginUrl() : 
instanceUrl) + OAUTH2_REVOKE_PATH
+                + accessToken;
+            final Request logoutGet = 
httpClient.newRequest(logoutUrl).timeout(timeout, TimeUnit.MILLISECONDS);
             final ContentResponse logoutResponse = logoutGet.send();
 
             final int statusCode = logoutResponse.getStatus();
@@ -227,9 +298,7 @@ public class SalesforceSession implements Service {
                 LOG.info("Logout successful");
             } else {
                 throw new SalesforceException(
-                        String.format("Logout error, code: [%s] reason: [%s]",
-                                statusCode, reason),
-                        statusCode);
+                    String.format("Logout error, code: [%s] reason: [%s]", 
statusCode, reason), statusCode);
             }
 
         } catch (InterruptedException e) {

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
index 0f65a6a..987f7e1 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/LoginConfigHelper.java
@@ -23,65 +23,74 @@ import java.io.InputStream;
 import java.util.Properties;
 
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.jsse.KeyStoreParameters;
 import org.junit.Assert;
 
 public class LoginConfigHelper extends Assert {
 
     protected static final String TEST_LOGIN_PROPERTIES = 
"../test-salesforce-login.properties";
 
-    public static SalesforceLoginConfig getLoginConfig() throws IOException {
+    private static final LoginConfigHelper INSTANCE;
 
-        // load test-salesforce-login properties
-        Properties properties = new Properties();
-        InputStream stream = null;
+    static {
         try {
-            final SalesforceLoginConfig config;
-            stream = new FileInputStream(TEST_LOGIN_PROPERTIES);
-            properties.load(stream);
+            INSTANCE = new LoginConfigHelper();
+        } catch (final IOException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    private SalesforceLoginConfig config;
 
-            if (ObjectHelper.isEmpty(properties.getProperty("refreshToken"))) {
-                config = new SalesforceLoginConfig(
-                        properties.getProperty("loginUrl", 
SalesforceLoginConfig.DEFAULT_LOGIN_URL),
-                        properties.getProperty("clientId"),
-                        properties.getProperty("clientSecret"),
-                        properties.getProperty("userName"),
-                        properties.getProperty("password"),
-                        
Boolean.parseBoolean(properties.getProperty("lazyLogin", "false")));
-            } else {
-                config = new SalesforceLoginConfig(
-                        properties.getProperty("loginUrl", 
SalesforceLoginConfig.DEFAULT_LOGIN_URL),
-                        properties.getProperty("clientId"), //
-                        properties.getProperty("clientSecret"), //
-                        properties.getProperty("refreshToken"), //
-                        
Boolean.parseBoolean(properties.getProperty("lazyLogin", "false")));
-            }
-
-
-            assertNotNull("Null loginUrl", config.getLoginUrl());
-            assertNotNull("Null clientId", config.getClientId());
-            assertNotNull("Null clientSecret", config.getClientSecret());
-            if (ObjectHelper.isEmpty(properties.getProperty("refreshToken"))) {
-                assertNotNull("Null userName", config.getUserName());
-                assertNotNull("Null password", config.getPassword());
-            } else {
-                assertNotNull("Null refreshToken", config.getRefreshToken());
-            }
-
-
-            return config;
-
-        } catch (FileNotFoundException e) {
-            throw new FileNotFoundException("Create a properties file named "
-                + TEST_LOGIN_PROPERTIES + " with clientId, clientSecret, 
userName, and password or with clientId, clientSecret and refreshToken"
+    private final Properties properties;
+
+    public LoginConfigHelper() throws IOException {
+        // load test-salesforce-login properties
+        try (InputStream stream = new FileInputStream(TEST_LOGIN_PROPERTIES);) 
{
+            properties = new Properties();
+            properties.load(stream);
+        } catch (final FileNotFoundException ignored) {
+            throw new FileNotFoundException("Create a properties file named " 
+ TEST_LOGIN_PROPERTIES
+                + " with clientId, clientSecret, userName, and password or 
with clientId, clientSecret and refreshToken"
                 + " for a Salesforce account with Merchandise and Invoice 
objects from Salesforce Guides.");
-        } finally {
-            if (stream != null) {
-                try {
-                    stream.close();
-                } catch (IOException ignore) {
-                }
-            }
         }
+
+        final boolean hasPassword = 
ObjectHelper.isNotEmpty(properties.getProperty("password"));
+        final boolean hasRefreshToken = 
ObjectHelper.isNotEmpty(properties.getProperty("refreshToken"));
+        final boolean hasKeystore = 
ObjectHelper.isNotEmpty(properties.getProperty("keystore.resource"));
+
+        final boolean lazyLogin = 
Boolean.parseBoolean(properties.getProperty("lazyLogin", "false"));
+        final String loginUrl = properties.getProperty("loginUrl", 
SalesforceLoginConfig.DEFAULT_LOGIN_URL);
+        final String clientId = properties.getProperty("clientId");
+        final String clientSecret = properties.getProperty("clientSecret");
+        final String username = properties.getProperty("userName");
+
+        if (hasPassword) {
+            config = new SalesforceLoginConfig(loginUrl, clientId, 
clientSecret, username,
+                properties.getProperty("password"), lazyLogin);
+        } else if (hasRefreshToken) {
+            config = new SalesforceLoginConfig(loginUrl, clientId, //
+                clientSecret, //
+                properties.getProperty("refreshToken"), //
+                lazyLogin);
+        } else if (hasKeystore) {
+            final KeyStoreParameters keystore = new KeyStoreParameters();
+            keystore.setResource(properties.getProperty("keystore.resource"));
+            keystore.setType(properties.getProperty("keystore.type"));
+            keystore.setPassword(properties.getProperty("keystore.password"));
+            config = new SalesforceLoginConfig(loginUrl, clientId, username, 
keystore, lazyLogin);
+        } else {
+            throw new IllegalArgumentException("Must specifiy parameters in " 
+ TEST_LOGIN_PROPERTIES);
+        }
+
+    }
+
+    public static SalesforceLoginConfig getLoginConfig() {
+        return INSTANCE.config;
+    }
+
+    public static Properties testLoginProperties() {
+        return INSTANCE.properties;
     }
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceJwtBearerTokenFlowIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceJwtBearerTokenFlowIntegrationTest.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceJwtBearerTokenFlowIntegrationTest.java
new file mode 100644
index 0000000..5a799c9
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/SalesforceJwtBearerTokenFlowIntegrationTest.java
@@ -0,0 +1,56 @@
+/**
+ * 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.salesforce;
+
+import java.util.Properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.salesforce.api.dto.Limits;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.apache.camel.util.jsse.KeyStoreParameters;
+import org.junit.Test;
+
+public class SalesforceJwtBearerTokenFlowIntegrationTest extends 
CamelTestSupport {
+
+    @Test
+    public void shouldLoginUsingJwtBearerToken() {
+        final Limits limits = template.requestBody("salesforce:limits", null, 
Limits.class);
+
+        assertNotNull(limits);
+    }
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        final CamelContext camelContext = super.createCamelContext();
+
+        final SalesforceComponent salesforce = new SalesforceComponent();
+        final Properties properties = LoginConfigHelper.testLoginProperties();
+        salesforce.setClientId(properties.getProperty("clientId"));
+        salesforce.setUserName(properties.getProperty("userName"));
+        salesforce.setLoginUrl(properties.getProperty("loginUrl"));
+
+        KeyStoreParameters keystore = new KeyStoreParameters();
+        keystore.setResource(properties.getProperty("keystore.resource"));
+        keystore.setType(properties.getProperty("keystore.type"));
+        keystore.setPassword(properties.getProperty("keystore.password"));
+        salesforce.setKeystore(keystore);
+
+        camelContext.addComponent("salesforce", salesforce);
+
+        return camelContext;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SalesforceSessionTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SalesforceSessionTest.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SalesforceSessionTest.java
new file mode 100644
index 0000000..d59961a
--- /dev/null
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SalesforceSessionTest.java
@@ -0,0 +1,54 @@
+/**
+ * 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.salesforce.internal;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import org.apache.camel.component.salesforce.SalesforceHttpClient;
+import org.apache.camel.component.salesforce.SalesforceLoginConfig;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.util.jsse.KeyStoreParameters;
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+
+public class SalesforceSessionTest {
+
+    private KeyStoreParameters parameters;
+
+    public SalesforceSessionTest() {
+        parameters = new KeyStoreParameters();
+        parameters.setResource("test.p12");
+        parameters.setType("PKCS12");
+        parameters.setPassword("password");
+    }
+
+    @Test
+    public void shouldGenerateJwtTokens() throws GeneralSecurityException, 
IOException {
+        SalesforceLoginConfig config = new 
SalesforceLoginConfig("https://login.salesforce.com";, "ABCD", "username",
+            parameters, true);
+
+        SalesforceSession session = new SalesforceSession(new 
DefaultCamelContext(), mock(SalesforceHttpClient.class),
+            1, config);
+
+        String jwtAssertion = session.generateJwtAssertion();
+
+        Assert.assertNotNull(jwtAssertion);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
index c78720a..81396c2 100644
--- 
a/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
+++ 
b/components/camel-salesforce/camel-salesforce-component/src/test/java/org/apache/camel/component/salesforce/internal/SessionIntegrationTest.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.salesforce.internal;
 
 import org.apache.camel.component.salesforce.LoginConfigHelper;
 import org.apache.camel.component.salesforce.SalesforceHttpClient;
+import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.util.jsse.SSLContextParameters;
 import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Assert;
@@ -43,7 +44,7 @@ public class SessionIntegrationTest extends Assert implements 
SalesforceSession.
         final SalesforceHttpClient httpClient = new 
SalesforceHttpClient(sslContextFactory);
         httpClient.setConnectTimeout(TIMEOUT);
 
-        final SalesforceSession session = new SalesforceSession(
+        final SalesforceSession session = new SalesforceSession(new 
DefaultCamelContext(),
             httpClient, TIMEOUT, LoginConfigHelper.getLoginConfig());
         session.addListener(this);
         httpClient.setSession(session);

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-component/src/test/resources/test.p12
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-component/src/test/resources/test.p12
 
b/components/camel-salesforce/camel-salesforce-component/src/test/resources/test.p12
new file mode 100644
index 0000000..976157a
Binary files /dev/null and 
b/components/camel-salesforce/camel-salesforce-component/src/test/resources/test.p12
 differ

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
index 38ec8ab..08ee1ab 100644
--- 
a/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
+++ 
b/components/camel-salesforce/camel-salesforce-maven-plugin/src/main/java/org/apache/camel/maven/CamelSalesforceMojo.java
@@ -61,6 +61,7 @@ import 
org.apache.camel.component.salesforce.internal.SalesforceSession;
 import org.apache.camel.component.salesforce.internal.client.DefaultRestClient;
 import org.apache.camel.component.salesforce.internal.client.RestClient;
 import 
org.apache.camel.component.salesforce.internal.client.SyncResponseCallback;
+import org.apache.camel.impl.DefaultCamelContext;
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.ObjectHelper;
 import org.apache.camel.util.jsse.SSLContextParameters;
@@ -576,7 +577,7 @@ public class CamelSalesforceMojo extends AbstractMojo {
         }
 
         // set session before calling start()
-        final SalesforceSession session = new SalesforceSession(httpClient,
+        final SalesforceSession session = new SalesforceSession(new 
DefaultCamelContext(), httpClient,
             httpClient.getTimeout(),
             new SalesforceLoginConfig(loginUrl, clientId, clientSecret, 
userName, password, false));
         httpClient.setSession(session);

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/components/camel-salesforce/it/resources/salesforce/connectedApps/CamelSalesforceIntegrationTests.connectedApp
----------------------------------------------------------------------
diff --git 
a/components/camel-salesforce/it/resources/salesforce/connectedApps/CamelSalesforceIntegrationTests.connectedApp
 
b/components/camel-salesforce/it/resources/salesforce/connectedApps/CamelSalesforceIntegrationTests.connectedApp
index 4afdf5d..59105f1 100644
--- 
a/components/camel-salesforce/it/resources/salesforce/connectedApps/CamelSalesforceIntegrationTests.connectedApp
+++ 
b/components/camel-salesforce/it/resources/salesforce/connectedApps/CamelSalesforceIntegrationTests.connectedApp
@@ -20,6 +20,7 @@
     <label>CamelSalesforceIntegrationTests</label>
     <oauthConfig>
         
<callbackUrl>https://login.salesforce.com/services/oauth2/success</callbackUrl>
+        
<certificate>MIIC1TCCAb2gAwIBAgIEM3ZMGjANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9TYWxlc2ZvcmNlIHRlc3QwIBcNMTcwMzE0MjIxMjU0WhgPMjExNzAyMTgyMjEyNTRaMBoxGDAWBgNVBAMTD1NhbGVzZm9yY2UgdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbZinVCZerzZvyyQlfE6nMpEQRfVsjpcfT01UTG/bwzWorP7YRpGkDW7Q4eu6IPrHtohkhM3JtsSVka5jfS1iEguMXLdNkEyMjMiBrWJeyGfcISF1yazgqLxxwcwGjMn3C9xV5tBxiRSqtMrV1iRx3fxmLue1UnZjSyUaG+Vi+FcKxqre5ixApeDCZHLONxBy3mjWK4GIeBBbUqQqy3LNrT6B34WdNX8vTslpTKOlmLyycEI/Rx+A4lNaultrJHdnRhGBrPwYinlV/wdramaQFL+ltqxQw6A5FBg9VjDEEd8JGv6OZ7aA/3mvjTbX5MaLj+aLJQyT2+XzDSAtDgOhMCAwEAAaMhMB8wHQYDVR0OBBYEFDM0jGtarY5uTVLThBEnXMUqDlyDMA0GCSqGSIb3DQEBCwUAA4IBAQCJtIsP5foO84sNwVMGwPiaoQUPE+cN73Tg63FSef36FEei6B3UnsFZnlcz9WGIL0G4PUjQro5z7/gMAHGehPQjoUEzKihdoNncbvKa9Yfuw4eO98YIp2t5OnOGQpDQWN9JO0On0tu+4rsgkJn8fZtzTPViS2Vhssi65DpWYydKWvEbbYw6oiPMH9T2mQy11lxSwNBngBy4ZF4hCyEVpvSe6Mr2q+jxgjCwMAqX+XofmEpfHaJXGy8lgtzow0oT8X4ymsV1JR0erw0dsbch9pTsG7YXcNFIEm50DctQEikoWxkAvIsZIHgujWkrjQlEsXZp/MS4OuNj6yWWlCaK/QM3</ce
 rtificate>
         
<consumerKey>3MVG9HxRZv05HarQ5D2to.ylPaUg7uaFqGqE2wN6_RRaHM9PTa3SWT8UwKJzXAyCujHrfObkUy7oZqiBUyfGl</consumerKey>
         <scopes>Api</scopes>
         <scopes>RefreshToken</scopes>

http://git-wip-us.apache.org/repos/asf/camel/blob/032047c3/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
----------------------------------------------------------------------
diff --git 
a/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
 
b/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
index dbff830..c70fb66 100644
--- 
a/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
+++ 
b/platforms/spring-boot/components-starter/camel-salesforce-starter/src/main/java/org/apache/camel/component/salesforce/springboot/SalesforceComponentConfiguration.java
@@ -28,6 +28,7 @@ import 
org.apache.camel.component.salesforce.api.dto.bulk.ContentType;
 import org.apache.camel.component.salesforce.internal.PayloadFormat;
 import org.apache.camel.component.salesforce.internal.dto.NotifyForFieldsEnum;
 import 
org.apache.camel.component.salesforce.internal.dto.NotifyForOperationsEnum;
+import org.apache.camel.util.jsse.KeyStoreParameters;
 import org.apache.camel.util.jsse.SSLContextParameters;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.boot.context.properties.NestedConfigurationProperty;
@@ -58,6 +59,11 @@ public class SalesforceComponentConfiguration {
      */
     private String clientSecret;
     /**
+     * KeyStoreParameters to use in OAuth 2.0 JWT Bearer Token Flow.
+     */
+    @NestedConfigurationProperty
+    private KeyStoreParameters keystore;
+    /**
      * Salesforce connected application Consumer token
      */
     private String refreshToken;
@@ -176,6 +182,14 @@ public class SalesforceComponentConfiguration {
         this.clientSecret = clientSecret;
     }
 
+    public KeyStoreParameters getKeystore() {
+        return keystore;
+    }
+
+    public void setKeystore(KeyStoreParameters keystore) {
+        this.keystore = keystore;
+    }
+
     public String getRefreshToken() {
         return refreshToken;
     }
@@ -340,96 +354,6 @@ public class SalesforceComponentConfiguration {
         this.resolvePropertyPlaceholders = resolvePropertyPlaceholders;
     }
 
-    public static class SalesforceLoginConfigNestedConfiguration {
-        public static final Class CAMEL_NESTED_CLASS = 
org.apache.camel.component.salesforce.SalesforceLoginConfig.class;
-        /**
-         * Salesforce login URL, defaults to https://login.salesforce.com
-         */
-        private String loginUrl;
-        /**
-         * Salesforce connected application Consumer Key
-         */
-        private String clientId;
-        /**
-         * Salesforce connected application Consumer Secret
-         */
-        private String clientSecret;
-        /**
-         * Salesforce connected application Consumer token
-         */
-        private String refreshToken;
-        /**
-         * Salesforce account user name
-         */
-        private String userName;
-        /**
-         * Salesforce account password
-         */
-        private String password;
-        /**
-         * Flag to enable/disable lazy OAuth, default is false. When enabled,
-         * OAuth token retrieval or generation is not done until the first API
-         * call
-         */
-        private Boolean lazyLogin;
-
-        public String getLoginUrl() {
-            return loginUrl;
-        }
-
-        public void setLoginUrl(String loginUrl) {
-            this.loginUrl = loginUrl;
-        }
-
-        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 String getRefreshToken() {
-            return refreshToken;
-        }
-
-        public void setRefreshToken(String refreshToken) {
-            this.refreshToken = refreshToken;
-        }
-
-        public String getUserName() {
-            return userName;
-        }
-
-        public void setUserName(String userName) {
-            this.userName = userName;
-        }
-
-        public String getPassword() {
-            return password;
-        }
-
-        public void setPassword(String password) {
-            this.password = password;
-        }
-
-        public Boolean getLazyLogin() {
-            return lazyLogin;
-        }
-
-        public void setLazyLogin(Boolean lazyLogin) {
-            this.lazyLogin = lazyLogin;
-        }
-    }
-
     public static class SalesforceEndpointConfigNestedConfiguration {
         public static final Class CAMEL_NESTED_CLASS = 
org.apache.camel.component.salesforce.SalesforceEndpointConfig.class;
         /**
@@ -1006,4 +930,108 @@ public class SalesforceComponentConfiguration {
             this.approvalSkipEntryCriteria = approvalSkipEntryCriteria;
         }
     }
+
+    public static class SalesforceLoginConfigNestedConfiguration {
+        public static final Class CAMEL_NESTED_CLASS = 
org.apache.camel.component.salesforce.SalesforceLoginConfig.class;
+        /**
+         * Salesforce login URL, defaults to https://login.salesforce.com
+         */
+        private String loginUrl;
+        /**
+         * Salesforce connected application Consumer Key
+         */
+        private String clientId;
+        /**
+         * Salesforce connected application Consumer Secret
+         */
+        private String clientSecret;
+        /**
+         * Keystore parameters for keystore containing certificate and private
+         * key needed for OAuth 2.0 JWT Bearer Token Flow.
+         */
+        @NestedConfigurationProperty
+        private KeyStoreParameters keystore;
+        /**
+         * Salesforce connected application Consumer token
+         */
+        private String refreshToken;
+        /**
+         * Salesforce account user name
+         */
+        private String userName;
+        /**
+         * Salesforce account password
+         */
+        private String password;
+        /**
+         * Flag to enable/disable lazy OAuth, default is false. When enabled,
+         * OAuth token retrieval or generation is not done until the first API
+         * call
+         */
+        private Boolean lazyLogin;
+
+        public String getLoginUrl() {
+            return loginUrl;
+        }
+
+        public void setLoginUrl(String loginUrl) {
+            this.loginUrl = loginUrl;
+        }
+
+        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 KeyStoreParameters getKeystore() {
+            return keystore;
+        }
+
+        public void setKeystore(KeyStoreParameters keystore) {
+            this.keystore = keystore;
+        }
+
+        public String getRefreshToken() {
+            return refreshToken;
+        }
+
+        public void setRefreshToken(String refreshToken) {
+            this.refreshToken = refreshToken;
+        }
+
+        public String getUserName() {
+            return userName;
+        }
+
+        public void setUserName(String userName) {
+            this.userName = userName;
+        }
+
+        public String getPassword() {
+            return password;
+        }
+
+        public void setPassword(String password) {
+            this.password = password;
+        }
+
+        public Boolean getLazyLogin() {
+            return lazyLogin;
+        }
+
+        public void setLazyLogin(Boolean lazyLogin) {
+            this.lazyLogin = lazyLogin;
+        }
+    }
 }
\ No newline at end of file

Reply via email to