diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java
index 7b212c9d8..076d35693 100644
--- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java
+++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdk.java
@@ -1,12 +1,10 @@
package com.symphony.bdk.core;
import com.symphony.bdk.core.activity.ActivityRegistry;
-import com.symphony.bdk.core.auth.AuthSession;
-import com.symphony.bdk.core.auth.AuthenticatorFactory;
-import com.symphony.bdk.core.auth.ExtensionAppAuthenticator;
-import com.symphony.bdk.core.auth.OboAuthenticator;
+import com.symphony.bdk.core.auth.*;
import com.symphony.bdk.core.auth.exception.AuthInitializationException;
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
+import com.symphony.bdk.core.auth.impl.AuthenticatorFactoryImpl;
import com.symphony.bdk.core.client.ApiClientFactory;
import com.symphony.bdk.core.config.exception.BotNotConfiguredException;
import com.symphony.bdk.core.config.model.BdkConfig;
@@ -103,7 +101,7 @@ protected SymphonyBdk(
}
if (authenticatorFactory == null) {
- authenticatorFactory = new AuthenticatorFactory(this.config, apiClientFactory);
+ authenticatorFactory = new AuthenticatorFactoryImpl(this.config, apiClientFactory);
}
this.oboAuthenticator = config.isOboConfigured() ? authenticatorFactory.getOboAuthenticator() : null;
diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdkBuilder.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdkBuilder.java
index fa69a479a..af73fbbf1 100644
--- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdkBuilder.java
+++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/SymphonyBdkBuilder.java
@@ -1,6 +1,7 @@
package com.symphony.bdk.core;
import com.symphony.bdk.core.auth.AuthenticatorFactory;
+import com.symphony.bdk.core.auth.impl.AuthenticatorFactoryImpl;
import com.symphony.bdk.core.auth.exception.AuthInitializationException;
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
import com.symphony.bdk.core.client.ApiClientFactory;
@@ -22,7 +23,7 @@
* Fluent builder for advanced configuration of the {@link SymphonyBdk} entry point.
*
*
Please note that some of the parameters (such as {@link ApiClientBuilderProvider}, {@link ApiClientFactory} or
- * {@link AuthenticatorFactory}) have to be used with caution.
+ * {@link AuthenticatorFactoryImpl}) have to be used with caution.
*/
@Generated
@API(status = API.Status.EXPERIMENTAL)
@@ -72,9 +73,9 @@ public SymphonyBdkBuilder apiClientFactory(@Nullable ApiClientFactory apiClientF
}
/**
- * With custom {@link AuthenticatorFactory} instance.
+ * With custom {@link AuthenticatorFactoryImpl} instance.
*
- * @param authenticatorFactory a custom {@link AuthenticatorFactory} instance.
+ * @param authenticatorFactory a custom {@link AuthenticatorFactoryImpl} instance.
* @return updated builder.
*/
public SymphonyBdkBuilder authenticatorFactory(@Nullable AuthenticatorFactory authenticatorFactory) {
@@ -115,7 +116,7 @@ public SymphonyBdk build() throws AuthUnauthorizedException, AuthInitializationE
}
if (this.authenticatorFactory == null) {
- this.authenticatorFactory = new AuthenticatorFactory(this.config, this.apiClientFactory);
+ this.authenticatorFactory = new AuthenticatorFactoryImpl(this.config, this.apiClientFactory);
}
final SymphonyBdk bdk = new SymphonyBdk(this.config, this.apiClientFactory, this.authenticatorFactory);
diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/AuthenticatorFactory.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/AuthenticatorFactory.java
index 7b862c7e7..5ee0e53f3 100644
--- a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/AuthenticatorFactory.java
+++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/AuthenticatorFactory.java
@@ -1,237 +1,46 @@
package com.symphony.bdk.core.auth;
-import static com.symphony.bdk.core.util.DeprecationLogger.logDeprecation;
-import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
-
import com.symphony.bdk.core.auth.exception.AuthInitializationException;
-import com.symphony.bdk.core.auth.impl.BotAuthenticatorCertImpl;
-import com.symphony.bdk.core.auth.impl.BotAuthenticatorRsaImpl;
-import com.symphony.bdk.core.auth.impl.ExtensionAppAuthenticatorCertImpl;
-import com.symphony.bdk.core.auth.impl.ExtensionAppAuthenticatorRsaImpl;
-import com.symphony.bdk.core.auth.impl.InMemoryTokensRepository;
-import com.symphony.bdk.core.auth.impl.OboAuthenticatorCertImpl;
-import com.symphony.bdk.core.auth.impl.OboAuthenticatorRsaImpl;
-import com.symphony.bdk.core.auth.jwt.JwtHelper;
-import com.symphony.bdk.core.client.ApiClientFactory;
-import com.symphony.bdk.core.config.model.BdkAuthenticationConfig;
-import com.symphony.bdk.core.config.model.BdkConfig;
-
-import com.symphony.bdk.core.service.version.AgentVersionService;
-
-import com.symphony.bdk.gen.api.SignalsApi;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.io.IOUtils;
import org.apiguardian.api.API;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
-import java.security.PrivateKey;
-
import javax.annotation.Nonnull;
/**
- * Factory class that provides new instances for the main authenticators :
+ * Factory responsible for creating different authenticators.
*
- * - {@link BotAuthenticator} : to authenticate the main Bot service account
- * - {@link OboAuthenticator} : to perform on-behalf-of authentication
+ * - Bot Authenticator: for authenticating the main bot service account
+ * - OBO Authenticator: for authenticating on behalf of a regular Symphony user
+ * - Extension App Authenticator: for authenticating an extension application
*
*/
-@Slf4j
@API(status = API.Status.STABLE)
-public class AuthenticatorFactory {
-
- private final BdkConfig config;
- private final ApiClientFactory apiClientFactory;
- private final ExtensionAppTokensRepository extensionAppTokensRepository;
-
- public AuthenticatorFactory(@Nonnull BdkConfig bdkConfig, @Nonnull ApiClientFactory apiClientFactory) {
- this(bdkConfig, apiClientFactory, new InMemoryTokensRepository());
- }
-
- public AuthenticatorFactory(@Nonnull BdkConfig bdkConfig, @Nonnull ApiClientFactory apiClientFactory,
- @Nonnull ExtensionAppTokensRepository extensionAppTokensRepository) {
- this.config = bdkConfig;
- this.apiClientFactory = apiClientFactory;
- this.extensionAppTokensRepository = extensionAppTokensRepository;
- }
+public interface AuthenticatorFactory {
/**
- * Creates a new instance of a {@link BotAuthenticator} service.
+ * Creates a new instance of a {@link BotAuthenticator}.
*
* @return a new {@link BotAuthenticator} instance.
+ * @throws AuthInitializationException if the authenticator cannot be instantiated.
*/
- public @Nonnull
- BotAuthenticator getBotAuthenticator() throws AuthInitializationException {
- if (this.config.getBot().isBothCertificateAndRsaConfigured()) {
- throw new AuthInitializationException(
- "Both of certificate and rsa authentication are configured. Only one of them should be provided.");
- }
- if (this.config.getBot().isCertificateAuthenticationConfigured()) {
- if (!this.config.getBot().isCertificateConfigurationValid()) {
- throw new AuthInitializationException(
- "Only one of certificate path or content should be configured for bot authentication.");
- }
- return new BotAuthenticatorCertImpl(
- this.config.getRetry(),
- this.config.getBot().getUsername(),
- this.config.getCommonJwt(),
- this.apiClientFactory.getLoginClient(),
- this.apiClientFactory.getSessionAuthClient(),
- this.apiClientFactory.getKeyAuthClient(),
- new AgentVersionService(new SignalsApi(this.apiClientFactory.getAgentClient()))
- );
- }
- if (this.config.getBot().isRsaAuthenticationConfigured()) {
- if (!this.config.getBot().isRsaConfigurationValid()) {
- throw new AuthInitializationException(
- "Only one of private key path or content should be configured for bot authentication.");
- }
- return new BotAuthenticatorRsaImpl(
- this.config.getRetry(),
- this.config.getBot().getUsername(),
- this.config.getCommonJwt(),
- this.loadPrivateKeyFromAuthenticationConfig(this.config.getBot()),
- this.apiClientFactory.getLoginClient(),
- this.apiClientFactory.getRelayClient(),
- new AgentVersionService(new SignalsApi(this.apiClientFactory.getAgentClient()))
- );
- }
- throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
- }
+ @Nonnull
+ BotAuthenticator getBotAuthenticator() throws AuthInitializationException;
/**
- * Creates a new instance of an {@link OboAuthenticator} service.
+ * Creates a new instance of a {@link OboAuthenticator}.
*
* @return a new {@link OboAuthenticator} instance.
+ * @throws AuthInitializationException if the authenticator cannot be instantiated.
*/
- public @Nonnull
- OboAuthenticator getOboAuthenticator() throws AuthInitializationException {
- if (this.config.getApp().isBothCertificateAndRsaConfigured()) {
- throw new AuthInitializationException(
- "Both of certificate and rsa authentication are configured. Only one of them should be provided.");
- }
- if (this.config.getApp().isCertificateAuthenticationConfigured()) {
- if (!this.config.getApp().isCertificateConfigurationValid()) {
- throw new AuthInitializationException(
- "Only one of certificate path or content should be configured for app authentication.");
- }
- return new OboAuthenticatorCertImpl(
- this.config.getRetry(),
- this.config.getApp().getAppId(),
- this.apiClientFactory.getExtAppSessionAuthClient()
- );
- }
- if (this.config.getApp().isRsaAuthenticationConfigured()) {
- if (!this.config.getApp().isRsaConfigurationValid()) {
- throw new AuthInitializationException(
- "Only one of private key path or content should be configured for app authentication.");
- }
- return new OboAuthenticatorRsaImpl(
- this.config.getRetry(),
- this.config.getApp().getAppId(),
- this.loadPrivateKeyFromAuthenticationConfig(this.config.getApp()),
- this.apiClientFactory.getLoginClient()
- );
- }
- throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
- }
+ @Nonnull
+ OboAuthenticator getOboAuthenticator() throws AuthInitializationException;
/**
- * Creates a new instance of an {@link ExtensionAppAuthenticator} service.
+ * Creates a new instance of a {@link ExtensionAppAuthenticator}.
*
* @return a new {@link ExtensionAppAuthenticator} instance.
+ * @throws AuthInitializationException if the authenticator cannot be instantiated.
*/
- public @Nonnull
- ExtensionAppAuthenticator getExtensionAppAuthenticator() throws AuthInitializationException {
- if (this.config.getApp().isBothCertificateAndRsaConfigured()) {
- throw new AuthInitializationException(
- "Both of certificate and rsa authentication are configured. Only one of them should be provided.");
- }
- if (this.config.getApp().isCertificateAuthenticationConfigured()) {
- if (!this.config.getApp().isCertificateConfigurationValid()) {
- throw new AuthInitializationException(
- "Only one of certificate path or content should be configured for app authentication.");
- }
- return new ExtensionAppAuthenticatorCertImpl(
- this.config.getRetry(),
- this.config.getApp().getAppId(),
- this.apiClientFactory.getExtAppSessionAuthClient(),
- extensionAppTokensRepository);
- }
- if (this.config.getApp().isRsaAuthenticationConfigured()) {
- if (!this.config.getApp().isRsaConfigurationValid()) {
- throw new AuthInitializationException(
- "Only one of private key path or content should be configured for app authentication.");
- }
- return new ExtensionAppAuthenticatorRsaImpl(
- this.config.getRetry(),
- this.config.getApp().getAppId(),
- this.loadPrivateKeyFromAuthenticationConfig(this.config.getApp()),
- this.apiClientFactory.getLoginClient(),
- this.apiClientFactory.getPodClient(),
- extensionAppTokensRepository
- );
- }
- throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
- }
-
- private PrivateKey loadPrivateKeyFromAuthenticationConfig(BdkAuthenticationConfig config)
- throws AuthInitializationException {
- String privateKeyPath = "";
- try {
- String privateKey;
- if (config.getPrivateKey() != null && config.getPrivateKey().isConfigured()) {
- if (isNotEmpty(config.getPrivateKey().getContent())) {
- privateKey = new String(config.getPrivateKey().getContent(), StandardCharsets.UTF_8);
- } else {
- privateKeyPath = config.getPrivateKey().getPath();
- log.debug("Loading RSA privateKey from path : {}", privateKeyPath);
- privateKey = loadPrivateKey(privateKeyPath);
- }
- } else {
- logDeprecation("RSA private key should be configured under \"privateKey\" field");
- if (isNotEmpty(config.getPrivateKeyContent())) {
- privateKey = new String(config.getPrivateKeyContent(), StandardCharsets.UTF_8);
- } else {
- privateKeyPath = config.getPrivateKeyPath();
- log.debug("Loading RSA privateKey from path : {}", privateKeyPath);
- privateKey = loadPrivateKey(privateKeyPath);
- }
- }
- return JwtHelper.parseRsaPrivateKey(privateKey);
- } catch (GeneralSecurityException e) {
- final String message = String.format("Unable to parse RSA Private Key from path %s. Check if the format is "
- + "correct.", privateKeyPath);
- throw new AuthInitializationException(message, e);
- } catch (IOException e) {
- final String message = "Unable to read or find RSA Private Key from path " + privateKeyPath;
- throw new AuthInitializationException(message, e);
- }
- }
-
- private static String loadPrivateKey(String privateKeyPath) throws IOException, AuthInitializationException {
- InputStream is;
-
- // useful for testing when private key is located into resources
- if (privateKeyPath.startsWith("classpath:")) {
- log.warn("Warning: Keeping RSA private keys into project resources is dangerous. "
- + "You should consider another location for production.");
- is = AuthenticatorFactory.class.getResourceAsStream(privateKeyPath.replace("classpath:", ""));
- if (is == null) {
- throw new AuthInitializationException(
- "Unable to find RSA private key as classpath resource from: " + privateKeyPath);
- }
- try (InputStream resourceStream = is) {
- return IOUtils.toString(resourceStream, StandardCharsets.UTF_8);
- }
- } else {
- try (InputStream fileStream = new FileInputStream(privateKeyPath)) {
- return IOUtils.toString(fileStream, StandardCharsets.UTF_8);
- }
- }
- }
+ @Nonnull
+ ExtensionAppAuthenticator getExtensionAppAuthenticator() throws AuthInitializationException;
}
diff --git a/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthenticatorFactoryImpl.java b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthenticatorFactoryImpl.java
new file mode 100644
index 000000000..5e18bb5aa
--- /dev/null
+++ b/symphony-bdk-core/src/main/java/com/symphony/bdk/core/auth/impl/AuthenticatorFactoryImpl.java
@@ -0,0 +1,237 @@
+package com.symphony.bdk.core.auth.impl;
+
+import static com.symphony.bdk.core.util.DeprecationLogger.logDeprecation;
+import static org.apache.commons.lang3.ObjectUtils.isNotEmpty;
+
+import com.symphony.bdk.core.auth.*;
+import com.symphony.bdk.core.auth.exception.AuthInitializationException;
+import com.symphony.bdk.core.auth.jwt.JwtHelper;
+import com.symphony.bdk.core.client.ApiClientFactory;
+import com.symphony.bdk.core.config.model.BdkAuthenticationConfig;
+import com.symphony.bdk.core.config.model.BdkConfig;
+
+import com.symphony.bdk.core.service.version.AgentVersionService;
+
+import com.symphony.bdk.gen.api.SignalsApi;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
+import org.apiguardian.api.API;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Factory class that provides new instances for the main authenticators :
+ *
+ * - {@link BotAuthenticator} : to authenticate the main Bot service account
+ * - {@link OboAuthenticator} : to perform on-behalf-of authentication
+ *
+ */
+@Slf4j
+@API(status = API.Status.INTERNAL)
+public class AuthenticatorFactoryImpl implements AuthenticatorFactory {
+
+ private final BdkConfig config;
+ private final ApiClientFactory apiClientFactory;
+ private final ExtensionAppTokensRepository extensionAppTokensRepository;
+
+ public AuthenticatorFactoryImpl(@Nonnull BdkConfig bdkConfig, @Nonnull ApiClientFactory apiClientFactory) {
+ this(bdkConfig, apiClientFactory, new InMemoryTokensRepository());
+ }
+
+ public AuthenticatorFactoryImpl(@Nonnull BdkConfig bdkConfig, @Nonnull ApiClientFactory apiClientFactory,
+ @Nonnull ExtensionAppTokensRepository extensionAppTokensRepository) {
+ this.config = bdkConfig;
+ this.apiClientFactory = apiClientFactory;
+ this.extensionAppTokensRepository = extensionAppTokensRepository;
+ }
+
+ /**
+ * Creates a new instance of a {@link BotAuthenticator} service.
+ *
+ * @return a new {@link BotAuthenticator} instance.
+ */
+ @Nonnull
+ @Override
+ public
+ BotAuthenticator getBotAuthenticator() throws AuthInitializationException {
+ if (this.config.getBot().isBothCertificateAndRsaConfigured()) {
+ throw new AuthInitializationException(
+ "Both of certificate and rsa authentication are configured. Only one of them should be provided.");
+ }
+ if (this.config.getBot().isCertificateAuthenticationConfigured()) {
+ if (!this.config.getBot().isCertificateConfigurationValid()) {
+ throw new AuthInitializationException(
+ "Only one of certificate path or content should be configured for bot authentication.");
+ }
+ return new BotAuthenticatorCertImpl(
+ this.config.getRetry(),
+ this.config.getBot().getUsername(),
+ this.config.getCommonJwt(),
+ this.apiClientFactory.getLoginClient(),
+ this.apiClientFactory.getSessionAuthClient(),
+ this.apiClientFactory.getKeyAuthClient(),
+ new AgentVersionService(new SignalsApi(this.apiClientFactory.getAgentClient()))
+ );
+ }
+ if (this.config.getBot().isRsaAuthenticationConfigured()) {
+ if (!this.config.getBot().isRsaConfigurationValid()) {
+ throw new AuthInitializationException(
+ "Only one of private key path or content should be configured for bot authentication.");
+ }
+ return new BotAuthenticatorRsaImpl(
+ this.config.getRetry(),
+ this.config.getBot().getUsername(),
+ this.config.getCommonJwt(),
+ this.loadPrivateKeyFromAuthenticationConfig(this.config.getBot()),
+ this.apiClientFactory.getLoginClient(),
+ this.apiClientFactory.getRelayClient(),
+ new AgentVersionService(new SignalsApi(this.apiClientFactory.getAgentClient()))
+ );
+ }
+ throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
+ }
+
+ /**
+ * Creates a new instance of an {@link OboAuthenticator} service.
+ *
+ * @return a new {@link OboAuthenticator} instance.
+ */
+ @Nonnull
+ @Override
+ public
+ OboAuthenticator getOboAuthenticator() throws AuthInitializationException {
+ if (this.config.getApp().isBothCertificateAndRsaConfigured()) {
+ throw new AuthInitializationException(
+ "Both of certificate and rsa authentication are configured. Only one of them should be provided.");
+ }
+ if (this.config.getApp().isCertificateAuthenticationConfigured()) {
+ if (!this.config.getApp().isCertificateConfigurationValid()) {
+ throw new AuthInitializationException(
+ "Only one of certificate path or content should be configured for app authentication.");
+ }
+ return new OboAuthenticatorCertImpl(
+ this.config.getRetry(),
+ this.config.getApp().getAppId(),
+ this.apiClientFactory.getExtAppSessionAuthClient()
+ );
+ }
+ if (this.config.getApp().isRsaAuthenticationConfigured()) {
+ if (!this.config.getApp().isRsaConfigurationValid()) {
+ throw new AuthInitializationException(
+ "Only one of private key path or content should be configured for app authentication.");
+ }
+ return new OboAuthenticatorRsaImpl(
+ this.config.getRetry(),
+ this.config.getApp().getAppId(),
+ this.loadPrivateKeyFromAuthenticationConfig(this.config.getApp()),
+ this.apiClientFactory.getLoginClient()
+ );
+ }
+ throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
+ }
+
+ /**
+ * Creates a new instance of an {@link ExtensionAppAuthenticator} service.
+ *
+ * @return a new {@link ExtensionAppAuthenticator} instance.
+ */
+ @Nonnull
+ @Override
+ public
+ ExtensionAppAuthenticator getExtensionAppAuthenticator() throws AuthInitializationException {
+ if (this.config.getApp().isBothCertificateAndRsaConfigured()) {
+ throw new AuthInitializationException(
+ "Both of certificate and rsa authentication are configured. Only one of them should be provided.");
+ }
+ if (this.config.getApp().isCertificateAuthenticationConfigured()) {
+ if (!this.config.getApp().isCertificateConfigurationValid()) {
+ throw new AuthInitializationException(
+ "Only one of certificate path or content should be configured for app authentication.");
+ }
+ return new ExtensionAppAuthenticatorCertImpl(
+ this.config.getRetry(),
+ this.config.getApp().getAppId(),
+ this.apiClientFactory.getExtAppSessionAuthClient(),
+ extensionAppTokensRepository);
+ }
+ if (this.config.getApp().isRsaAuthenticationConfigured()) {
+ if (!this.config.getApp().isRsaConfigurationValid()) {
+ throw new AuthInitializationException(
+ "Only one of private key path or content should be configured for app authentication.");
+ }
+ return new ExtensionAppAuthenticatorRsaImpl(
+ this.config.getRetry(),
+ this.config.getApp().getAppId(),
+ this.loadPrivateKeyFromAuthenticationConfig(this.config.getApp()),
+ this.apiClientFactory.getLoginClient(),
+ this.apiClientFactory.getPodClient(),
+ extensionAppTokensRepository
+ );
+ }
+ throw new AuthInitializationException("Neither RSA private key nor certificate is configured.");
+ }
+
+ private PrivateKey loadPrivateKeyFromAuthenticationConfig(BdkAuthenticationConfig config)
+ throws AuthInitializationException {
+ String privateKeyPath = "";
+ try {
+ String privateKey;
+ if (config.getPrivateKey() != null && config.getPrivateKey().isConfigured()) {
+ if (isNotEmpty(config.getPrivateKey().getContent())) {
+ privateKey = new String(config.getPrivateKey().getContent(), StandardCharsets.UTF_8);
+ } else {
+ privateKeyPath = config.getPrivateKey().getPath();
+ log.debug("Loading RSA privateKey from path : {}", privateKeyPath);
+ privateKey = loadPrivateKey(privateKeyPath);
+ }
+ } else {
+ logDeprecation("RSA private key should be configured under \"privateKey\" field");
+ if (isNotEmpty(config.getPrivateKeyContent())) {
+ privateKey = new String(config.getPrivateKeyContent(), StandardCharsets.UTF_8);
+ } else {
+ privateKeyPath = config.getPrivateKeyPath();
+ log.debug("Loading RSA privateKey from path : {}", privateKeyPath);
+ privateKey = loadPrivateKey(privateKeyPath);
+ }
+ }
+ return JwtHelper.parseRsaPrivateKey(privateKey);
+ } catch (GeneralSecurityException e) {
+ final String message = String.format("Unable to parse RSA Private Key from path %s. Check if the format is "
+ + "correct.", privateKeyPath);
+ throw new AuthInitializationException(message, e);
+ } catch (IOException e) {
+ final String message = "Unable to read or find RSA Private Key from path " + privateKeyPath;
+ throw new AuthInitializationException(message, e);
+ }
+ }
+
+ private static String loadPrivateKey(String privateKeyPath) throws IOException, AuthInitializationException {
+ InputStream is;
+
+ // useful for testing when private key is located into resources
+ if (privateKeyPath.startsWith("classpath:")) {
+ log.warn("Warning: Keeping RSA private keys into project resources is dangerous. "
+ + "You should consider another location for production.");
+ is = AuthenticatorFactoryImpl.class.getResourceAsStream(privateKeyPath.replace("classpath:", ""));
+ if (is == null) {
+ throw new AuthInitializationException(
+ "Unable to find RSA private key as classpath resource from: " + privateKeyPath);
+ }
+ try (InputStream resourceStream = is) {
+ return IOUtils.toString(resourceStream, StandardCharsets.UTF_8);
+ }
+ } else {
+ try (InputStream fileStream = new FileInputStream(privateKeyPath)) {
+ return IOUtils.toString(fileStream, StandardCharsets.UTF_8);
+ }
+ }
+ }
+}
diff --git a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/auth/AuthenticatorFactoryTest.java b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/auth/AuthenticatorFactoryTest.java
index aadf71907..5c1b6e1b2 100644
--- a/symphony-bdk-core/src/test/java/com/symphony/bdk/core/auth/AuthenticatorFactoryTest.java
+++ b/symphony-bdk-core/src/test/java/com/symphony/bdk/core/auth/AuthenticatorFactoryTest.java
@@ -7,6 +7,7 @@
import static org.mockito.Mockito.when;
import com.symphony.bdk.core.auth.exception.AuthInitializationException;
+import com.symphony.bdk.core.auth.impl.AuthenticatorFactoryImpl;
import com.symphony.bdk.core.auth.impl.BotAuthenticatorCertImpl;
import com.symphony.bdk.core.auth.impl.BotAuthenticatorRsaImpl;
import com.symphony.bdk.core.auth.impl.ExtensionAppAuthenticatorCertImpl;
@@ -35,7 +36,7 @@
import java.util.function.Supplier;
/**
- * Test class for the {@link AuthenticatorFactory}.
+ * Test class for the {@link AuthenticatorFactoryImpl}.
*/
class AuthenticatorFactoryTest {
@@ -62,7 +63,7 @@ void testGetBotAuthenticatorWithValidPrivateKey(@TempDir Path tempDir) throws Au
return privateKeyPath.toAbsolutePath().toString();
});
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
final BotAuthenticator botAuth = factory.getBotAuthenticator();
assertNotNull(botAuth);
assertEquals(BotAuthenticatorRsaImpl.class, botAuth.getClass());
@@ -72,7 +73,7 @@ void testGetBotAuthenticatorWithValidPrivateKey(@TempDir Path tempDir) throws Au
void testGetBotAuthenticatorWithValidPrivateKeyInClasspath() throws AuthInitializationException {
final BdkConfig config = createRsaConfig(() -> "classpath:/keys/private-key.pem");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
final BotAuthenticator botAuth = factory.getBotAuthenticator();
assertNotNull(botAuth);
assertEquals(BotAuthenticatorRsaImpl.class, botAuth.getClass());
@@ -82,7 +83,7 @@ void testGetBotAuthenticatorWithValidPrivateKeyInClasspath() throws AuthInitiali
void testGetBotAuthenticatorWithPrivateKeyNotFoundInClasspath() {
final BdkConfig config = createRsaConfig(() -> "classpath:/keys/notfound.pem");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, () -> factory.getBotAuthenticator());
}
@@ -92,7 +93,7 @@ void testGetAuthenticatorWithValidPrivateKeyContent() throws AuthInitializationE
final BdkConfig config = new BdkConfig();
config.getBot().getPrivateKey().setContent(RSA_PRIVATE_KEY.getBytes());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
final BotAuthenticator botAuth = factory.getBotAuthenticator();
assertEquals(BotAuthenticatorRsaImpl.class, botAuth.getClass());
@@ -104,7 +105,7 @@ void testGetAuthenticatorWithInvalidPrivateKeyContent() {
final BdkConfig config = new BdkConfig();
config.getBot().getPrivateKey().setContent("invalid-key".getBytes());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
@@ -118,7 +119,7 @@ void testGetBotAuthenticatorWithInvalidPrivateKey(@TempDir Path tempDir) {
return privateKeyPath.toAbsolutePath().toString();
});
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
@@ -131,7 +132,7 @@ void testGetBotAuthenticatorWithInvalidPrivateKeyUsingDeprecatedField(@TempDir P
return privateKeyPath.toAbsolutePath().toString();
});
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
@@ -140,7 +141,7 @@ void testGetBotAuthenticatorWithNotFoundPrivateKey(@TempDir Path tempDir) {
final BdkConfig config = createRsaConfig(() -> tempDir.resolve(UUID.randomUUID().toString() + "-privateKey.pem").toAbsolutePath().toString());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
@@ -153,7 +154,7 @@ void testGetOboAuthenticatorWithValidPrivateKey(@TempDir Path tempDir) throws Au
return privateKeyPath.toAbsolutePath().toString();
});
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
final OboAuthenticator oboAuth = factory.getOboAuthenticator();
assertNotNull(oboAuth);
assertEquals(OboAuthenticatorRsaImpl.class, oboAuth.getClass());
@@ -165,7 +166,7 @@ void testGetBotCertificateAuthenticator() throws AuthInitializationException {
config.getBot().getCertificate().setPath("/path/to/cert/file.p12");
config.getBot().getCertificate().setPassword("password");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
BotAuthenticator botAuthenticator = factory.getBotAuthenticator();
assertNotNull(botAuthenticator);
assertEquals(BotAuthenticatorCertImpl.class, botAuthenticator.getClass());
@@ -177,7 +178,7 @@ void testGetOboCertificateAuthenticator() throws AuthInitializationException {
config.getApp().getCertificate().setPath("/path/to/cert/file.p12");
config.getApp().getCertificate().setPassword("password");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
OboAuthenticator oboAuthenticator = factory.getOboAuthenticator();
assertNotNull(oboAuthenticator);
assertEquals(OboAuthenticatorCertImpl.class, oboAuthenticator.getClass());
@@ -192,7 +193,7 @@ void testGetExtAppAuthenticatorWithValidPrivateKey(@TempDir Path tempDir) throws
return privateKeyPath.toAbsolutePath().toString();
});
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
final ExtensionAppAuthenticator botAuth = factory.getExtensionAppAuthenticator();
assertEquals(ExtensionAppAuthenticatorRsaImpl.class, botAuth.getClass());
@@ -204,7 +205,7 @@ void testGetExtAppAuthenticatorWithValidCertificatePath(@TempDir Path tempDir) t
config.getApp().getCertificate().setPath("/path/to/cert/file.p12");
config.getApp().getCertificate().setPassword("password");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
final ExtensionAppAuthenticator extAppAuthenticator = factory.getExtensionAppAuthenticator();
assertEquals(ExtensionAppAuthenticatorCertImpl.class, extAppAuthenticator.getClass());
@@ -219,7 +220,7 @@ void testGetAuthenticatorWithBothCertificatePathAndContentConfigured() {
config.getApp().getCertificate().setPath("/path/to/cert/file.p12");
config.getApp().getCertificate().setPassword("password");
config.getApp().getCertificate().setContent("certificate-content".getBytes());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
assertThrows(AuthInitializationException.class, factory::getExtensionAppAuthenticator);
@@ -233,7 +234,7 @@ void testGetAuthenticatorWithBothPrivateKeyPathAndContentConfigured() {
config.getBot().getPrivateKey().setContent("privatekey-content".getBytes());
config.getApp().getPrivateKey().setPath("/path/to/cert/privatekey.pem");
config.getApp().getPrivateKey().setContent("privatekey-content".getBytes());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
assertThrows(AuthInitializationException.class, factory::getExtensionAppAuthenticator);
@@ -249,7 +250,7 @@ void testGetExtAppAuthenticatorWithInvalidPrivateKey(@TempDir Path tempDir) {
return privateKeyPath.toAbsolutePath().toString();
});
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getExtensionAppAuthenticator);
}
@@ -259,7 +260,7 @@ void testGetExtAppAuthenticatorWithNotFoundPrivateKey(@TempDir Path tempDir) {
final BdkConfig config = createRsaConfig(() -> tempDir.resolve(UUID.randomUUID().toString() + "-privateKey.pem").toAbsolutePath().toString());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getExtensionAppAuthenticator);
}
@@ -269,7 +270,7 @@ void testGetAuthenticationRsaAndCertificateNotConfigured() {
final BdkConfig config = new BdkConfig();
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
assertThrows(AuthInitializationException.class, factory::getOboAuthenticator);
@@ -287,7 +288,7 @@ void testGetBotAuthenticatorBothRsaAndCertificateConfigured(@TempDir Path tempDi
config.getBot().getCertificate().setPath("/path/to/cert/file.p12");
config.getBot().getCertificate().setPassword("password");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
@@ -303,7 +304,7 @@ void testGetAppAuthenticatorBothRsaAndCertificateConfigured(@TempDir Path tempDi
config.getApp().getCertificate().setPath("/path/to/cert/file.p12");
config.getApp().getCertificate().setPassword("password");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getExtensionAppAuthenticator);
assertThrows(AuthInitializationException.class, factory::getOboAuthenticator);
@@ -321,7 +322,7 @@ void testGetAuthenticatorRsaInvalid(@TempDir Path tempDir) {
config.getBot().setPrivateKey(privateKey);
config.getApp().setPrivateKey(privateKey);
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
assertThrows(AuthInitializationException.class, factory::getExtensionAppAuthenticator);
@@ -335,7 +336,7 @@ void testGetAuthenticatorCertificateInvalid() {
config.getBot().getCertificate().setPath("/path/to/cert/cert.pem");
config.getBot().setCertificatePath("/path/to/cert/cert.pem");
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
@@ -347,7 +348,7 @@ void testGetAuthenticatorBothPathAndContentInCertificateField() {
config.getBot().getCertificate().setPath("/path/to/cert/cert.pem");
config.getBot().getCertificate().setContent("certificate-content".getBytes());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
@@ -359,7 +360,7 @@ void testGetAuthenticatorBothPathAndContentInPrivateKeyField() {
config.getBot().getPrivateKey().setPath("/path/to/cert/privatekey.pem");
config.getBot().getPrivateKey().setContent("privatekey-content".getBytes());
- final AuthenticatorFactory factory = new AuthenticatorFactory(config, DUMMY_API_CLIENT_FACTORY);
+ final AuthenticatorFactory factory = new AuthenticatorFactoryImpl(config, DUMMY_API_CLIENT_FACTORY);
assertThrows(AuthInitializationException.class, factory::getBotAuthenticator);
}
diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java
index 1719c2397..1ff4ef07a 100644
--- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java
+++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/main/java/com/symphony/bdk/spring/config/BdkCoreConfig.java
@@ -4,6 +4,7 @@
import com.symphony.bdk.core.auth.AuthSession;
import com.symphony.bdk.core.auth.AuthenticatorFactory;
+import com.symphony.bdk.core.auth.impl.AuthenticatorFactoryImpl;
import com.symphony.bdk.core.auth.ExtensionAppTokensRepository;
import com.symphony.bdk.core.auth.impl.OAuthSession;
import com.symphony.bdk.core.auth.impl.OAuthentication;
@@ -102,7 +103,7 @@ public ExtensionAppTokensRepository extensionAppTokensRepository() {
@ConditionalOnMissingBean
public AuthenticatorFactory authenticatorFactory(SymphonyBdkCoreProperties properties,
ApiClientFactory apiClientFactory, ExtensionAppTokensRepository extensionAppTokensRepository) {
- return new AuthenticatorFactory(properties, apiClientFactory, extensionAppTokensRepository);
+ return new AuthenticatorFactoryImpl(properties, apiClientFactory, extensionAppTokensRepository);
}
@Bean
diff --git a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java
index 8dad84753..aa77969ee 100644
--- a/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java
+++ b/symphony-bdk-spring/symphony-bdk-core-spring-boot-starter/src/test/java/com/symphony/bdk/spring/config/BdkCoreConfigTest.java
@@ -5,13 +5,10 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import com.symphony.bdk.core.auth.AuthSession;
-import com.symphony.bdk.core.auth.AuthenticatorFactory;
-import com.symphony.bdk.core.auth.BotAuthenticator;
-import com.symphony.bdk.core.auth.ExtensionAppAuthenticator;
-import com.symphony.bdk.core.auth.OboAuthenticator;
+import com.symphony.bdk.core.auth.*;
import com.symphony.bdk.core.auth.exception.AuthInitializationException;
import com.symphony.bdk.core.auth.exception.AuthUnauthorizedException;
+import com.symphony.bdk.core.auth.impl.AuthenticatorFactoryImpl;
import com.symphony.bdk.core.client.ApiClientFactory;
import com.symphony.bdk.core.config.model.BdkCommonJwtConfig;
import com.symphony.bdk.core.config.model.BdkConfig;
@@ -32,7 +29,7 @@ class BdkCoreConfigTest {
void shouldFailToCreateBotSession() throws Exception {
final BdkCoreConfig config = new BdkCoreConfig();
- final AuthenticatorFactory authFactory = mock(AuthenticatorFactory.class);
+ final AuthenticatorFactory authFactory = mock(AuthenticatorFactoryImpl.class);
final BotAuthenticator botAuthenticator = mock(BotAuthenticator.class);
when(botAuthenticator.authenticateBot()).thenThrow(AuthUnauthorizedException.class);
@@ -79,7 +76,7 @@ void shouldCreateSessionAuthApiClient() {
@Test
void shouldCreateExtensionAppAuthenticator() throws AuthInitializationException {
final BdkOboServiceConfig config = new BdkOboServiceConfig();
- final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactory.class);
+ final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactoryImpl.class);
final ExtensionAppAuthenticator appAuthenticator = mock(ExtensionAppAuthenticator.class);
when(authenticatorFactory.getExtensionAppAuthenticator()).thenReturn(appAuthenticator);
@@ -89,7 +86,7 @@ void shouldCreateExtensionAppAuthenticator() throws AuthInitializationException
@Test
void shouldFailCreateExtensionAppAuthenticator() throws AuthInitializationException {
final BdkOboServiceConfig config = new BdkOboServiceConfig();
- final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactory.class);
+ final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactoryImpl.class);
when(authenticatorFactory.getExtensionAppAuthenticator()).thenThrow(AuthInitializationException.class);
assertThrows(BeanInitializationException.class, () -> config.extensionAppAuthenticator(authenticatorFactory));
@@ -98,7 +95,7 @@ void shouldFailCreateExtensionAppAuthenticator() throws AuthInitializationExcept
@Test
void shouldCreateOboAuthenticator() throws AuthInitializationException {
final BdkOboServiceConfig config = new BdkOboServiceConfig();
- final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactory.class);
+ final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactoryImpl.class);
final OboAuthenticator oboAuthenticator = mock(OboAuthenticator.class);
when(authenticatorFactory.getOboAuthenticator()).thenReturn(oboAuthenticator);
@@ -108,7 +105,7 @@ void shouldCreateOboAuthenticator() throws AuthInitializationException {
@Test
void shouldFailCreateOboAuthenticator() throws AuthInitializationException {
final BdkOboServiceConfig config = new BdkOboServiceConfig();
- final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactory.class);
+ final AuthenticatorFactory authenticatorFactory = mock(AuthenticatorFactoryImpl.class);
when(authenticatorFactory.getOboAuthenticator()).thenThrow(AuthInitializationException.class);
assertThrows(BeanInitializationException.class, () -> config.oboAuthenticator(authenticatorFactory));