diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/pom.xml b/libs/teams/teams-chat-workflow-spring-boot-starter/pom.xml
index 46311a741..ac93ae548 100644
--- a/libs/teams/teams-chat-workflow-spring-boot-starter/pom.xml
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/pom.xml
@@ -77,6 +77,12 @@
azure-storage-blob
${azure-storage-blob.version}
+
+
+ com.azure
+ azure-identity
+ ${azure-identity.version}
+
com.azure
diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/AbstractTeamsConversations.java b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/AbstractTeamsConversations.java
index 58b810be3..d0f4ee3c3 100644
--- a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/AbstractTeamsConversations.java
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/AbstractTeamsConversations.java
@@ -21,7 +21,6 @@
import com.microsoft.bot.builder.teams.TeamsInfo;
import com.microsoft.bot.connector.ConnectorClient;
import com.microsoft.bot.connector.Conversations;
-import com.microsoft.bot.connector.authentication.MicrosoftAppCredentials;
import com.microsoft.bot.schema.Activity;
import com.microsoft.bot.schema.ChannelAccount;
import com.microsoft.bot.schema.ConversationAccount;
@@ -40,11 +39,11 @@
*/
public abstract class AbstractTeamsConversations implements TeamsConversations {
- private MicrosoftAppCredentials mac;
+ private SpringBotAppCredentials mac;
private BotFrameworkAdapter bfa;
private ChannelAccount botAccount;
- public AbstractTeamsConversations(BotFrameworkAdapter bfa, MicrosoftAppCredentials mac, ChannelAccount botAccount) {
+ public AbstractTeamsConversations(BotFrameworkAdapter bfa, SpringBotAppCredentials mac, ChannelAccount botAccount) {
super();
this.mac = mac;
this.bfa = bfa;
@@ -145,7 +144,7 @@ protected String getOneToOneConversationId(TeamsUser tu) {
try {
ConversationParameters cp = new ConversationParameters();
cp.setIsGroup(false);
- cp.setTenantId(mac.getChannelAuthTenant());
+ cp.setTenantId(mac.getTenantId());
cp.setMembers(Collections.singletonList(new ChannelAccount(tu.getKey())));
return getConversations().createConversation(cp).get().getId();
@@ -159,17 +158,17 @@ public ConversationAccount getConversationAccount(TeamsAddressable address) {
if (address instanceof TeamsUser) {
String chatForUser = getOneToOneConversationId((TeamsUser) address);
ConversationAccount ca = new ConversationAccount(chatForUser);
- ca.setTenantId(mac.getChannelAuthTenant());
+ ca.setTenantId(mac.getTenantId());
ca.setConversationType("personal");
return ca;
} else if (address instanceof TeamsChannel) {
ConversationAccount ca = new ConversationAccount(address.getKey());
- ca.setTenantId(mac.getChannelAuthTenant());
+ ca.setTenantId(mac.getTenantId());
ca.setConversationType("channel");
return ca;
} else if (address instanceof TeamsMultiwayChat) {
ConversationAccount ca = new ConversationAccount(address.getKey());
- ca.setTenantId(mac.getChannelAuthTenant());
+ ca.setTenantId(mac.getTenantId());
ca.setConversationType("groupChat");
return ca;
} else {
@@ -226,7 +225,7 @@ private TurnContext getWorkingTurnContext(TeamsAddressable ta) {
TurnContext[] holder = new TurnContext[1];
- bfa.continueConversation(mac.getAppId(), createConversationReference(ta), tc -> {
+ bfa.continueConversation(mac.getClientId(), createConversationReference(ta), tc -> {
holder[0] = tc;
return CompletableFuture.completedFuture(null);
}).get();
diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotAppCredentials.java b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotAppCredentials.java
new file mode 100644
index 000000000..1626cd312
--- /dev/null
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotAppCredentials.java
@@ -0,0 +1,15 @@
+package org.finos.springbot.teams.conversations;
+
+import com.azure.identity.ClientCertificateCredential;
+
+public interface SpringBotAppCredentials {
+
+ String getTenantId();
+
+ String getClientId();
+
+ ClientCertificateCredential getCredential();
+
+ String getToken();
+
+}
\ No newline at end of file
diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotMicrosoftAppCredentials.java b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotMicrosoftAppCredentials.java
new file mode 100644
index 000000000..cb2446fe3
--- /dev/null
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotMicrosoftAppCredentials.java
@@ -0,0 +1,70 @@
+package org.finos.springbot.teams.conversations;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Base64;
+
+import com.azure.core.credential.TokenRequestContext;
+import com.azure.identity.ClientCertificateCredential;
+import com.azure.identity.ClientCertificateCredentialBuilder;
+
+public class SpringBotMicrosoftAppCredentials implements SpringBotAppCredentials {
+
+ private String tenantId = null;
+ private String clientId = null;
+ private ClientCertificateCredential credential = null;
+
+ public SpringBotMicrosoftAppCredentials(String tenantId, String clientId, String certificate,
+ String certificatePassword) {
+ this.tenantId = tenantId;
+ this.clientId = clientId;
+ String pemContent = certificate;
+ try {
+
+ // Check for file extension and illegal path characters
+ boolean isFilePath = (certificate != null && (certificate.endsWith(".p12")));
+
+ if (certificate != null) {
+ if (!isFilePath) {
+ byte[] decode = Base64.getDecoder().decode(pemContent);
+
+ java.nio.file.Path tempFile = Files.createTempFile("cert", ".p12");
+ Files.write(tempFile, decode);
+ certificate = tempFile.toAbsolutePath().toString();
+ }
+
+ this.credential = new ClientCertificateCredentialBuilder().tenantId(tenantId).clientId(clientId)
+ .pemCertificate(Files.newInputStream(Paths.get(certificate)))
+ .clientCertificatePassword(certificatePassword).build();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to create certificate", e);
+ }
+
+ }
+
+ @Override
+ public String getTenantId() {
+ return tenantId;
+ }
+
+ @Override
+ public String getClientId() {
+ return clientId;
+ }
+
+ @Override
+ public ClientCertificateCredential getCredential() {
+ return credential;
+ }
+
+ @Override
+ public String getToken() {
+ return credential.getTokenSync(new TokenRequestContext().addScopes("https://graph.microsoft.com/.default"))
+ .getToken();
+ }
+
+
+}
\ No newline at end of file
diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/StateStorageBasedTeamsConversations.java b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/StateStorageBasedTeamsConversations.java
index 1a0562161..3716e3a2b 100644
--- a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/StateStorageBasedTeamsConversations.java
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/StateStorageBasedTeamsConversations.java
@@ -21,7 +21,6 @@
import org.finos.springbot.workflow.content.Chat;
import com.microsoft.bot.builder.BotFrameworkAdapter;
-import com.microsoft.bot.connector.authentication.MicrosoftAppCredentials;
import com.microsoft.bot.schema.ChannelAccount;
public class StateStorageBasedTeamsConversations extends AbstractTeamsConversations {
@@ -34,7 +33,7 @@ public class StateStorageBasedTeamsConversations extends AbstractTeamsConversati
protected final TeamsStateStorage tss;
- public StateStorageBasedTeamsConversations(BotFrameworkAdapter bfa, MicrosoftAppCredentials mac,
+ public StateStorageBasedTeamsConversations(BotFrameworkAdapter bfa, SpringBotAppCredentials mac,
ChannelAccount botAccount, TeamsStateStorage tss) {
super(bfa, mac, botAccount);
this.tss = tss;
diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/TeamsConversationsConfig.java b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/TeamsConversationsConfig.java
index 6fa6526ae..1fbbe491d 100644
--- a/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/TeamsConversationsConfig.java
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/TeamsConversationsConfig.java
@@ -11,7 +11,6 @@
import org.springframework.context.annotation.Bean;
import com.microsoft.bot.builder.BotFrameworkAdapter;
-import com.microsoft.bot.connector.authentication.MicrosoftAppCredentials;
import com.microsoft.bot.integration.AdapterWithErrorHandler;
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
import com.microsoft.bot.schema.ChannelAccount;
@@ -19,24 +18,32 @@
public class TeamsConversationsConfig extends BotDependencyConfiguration {
@Bean
- public MicrosoftAppCredentials microsoftCredentials(@Value("${teams.app.tennantId}") String tennantId) {
+ public SpringBotAppCredentials microsoftCredentials(@Value("${teams.app.tennantId}") String tennantId) {
com.microsoft.bot.integration.Configuration conf = getConfiguration();
- MicrosoftAppCredentials mac = new MicrosoftAppCredentials(
- conf.getProperty(MicrosoftAppCredentials.MICROSOFTAPPID),
- conf.getProperty(MicrosoftAppCredentials.MICROSOFTAPPPASSWORD),
- tennantId);
- return mac;
+
+ String clientId = conf.getProperty(com.microsoft.bot.connector.authentication.MicrosoftAppCredentials.MICROSOFTAPPID);
+
+ SpringBotAppCredentials out = new SpringBotMicrosoftAppCredentials(tennantId,
+ clientId, conf.getProperty("MicrosoftAppIdPemCertificate"), conf.getProperty("MicrosoftAppIdPemCertificatePassword"));
+
+// MicrosoftAppCredentials mac = new MicrosoftAppCredentials(
+// conf.getProperty(MicrosoftAppCredentials.MICROSOFTAPPID),
+// conf.getProperty(MicrosoftAppCredentials.MICROSOFTAPPPASSWORD),
+// tennantId);
+
+ return out;
}
+
@Bean
@ConditionalOnMissingBean
public TeamsConversations teamsConversations(
BotFrameworkAdapter bfa,
- MicrosoftAppCredentials mac,
+ SpringBotAppCredentials appCredentials,
@Value("${teams.bot.id:}") String id,
TeamsStateStorage teamsState) {
ChannelAccount botAccount = new ChannelAccount(id);
- return new StateStorageBasedTeamsConversations(bfa, mac, botAccount, teamsState);
+ return new StateStorageBasedTeamsConversations(bfa, appCredentials, botAccount, teamsState);
}
diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/MockTeamsConfiguration.java b/libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/MockTeamsConfiguration.java
index a82d3cac6..bb69065f5 100644
--- a/libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/MockTeamsConfiguration.java
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/MockTeamsConfiguration.java
@@ -1,8 +1,11 @@
package org.finos.springbot.teams;
+import org.finos.springbot.teams.conversations.MockSpringBotMicrosoftAppCredentials;
+import org.finos.springbot.teams.conversations.SpringBotAppCredentials;
import org.finos.springbot.tests.controller.OurController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
@@ -18,5 +21,11 @@ public LocalValidatorFactoryBean localValidatorFactoryBean() {
public OurController ourController() {
return new OurController();
}
+
+ @Bean
+ @Primary
+ public SpringBotAppCredentials dummyMicrosoftCredentials() {
+ return new MockSpringBotMicrosoftAppCredentials();
+ }
}
\ No newline at end of file
diff --git a/libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/conversations/MockSpringBotMicrosoftAppCredentials.java b/libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/conversations/MockSpringBotMicrosoftAppCredentials.java
new file mode 100644
index 000000000..18ca1b3ec
--- /dev/null
+++ b/libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/conversations/MockSpringBotMicrosoftAppCredentials.java
@@ -0,0 +1,27 @@
+package org.finos.springbot.teams.conversations;
+
+import com.azure.identity.ClientCertificateCredential;
+
+public class MockSpringBotMicrosoftAppCredentials implements SpringBotAppCredentials {
+
+ @Override
+ public String getTenantId() {
+ return "mock-tenant-id";
+ }
+
+ @Override
+ public String getClientId() {
+ return "mock-client-id";
+ }
+
+ @Override
+ public ClientCertificateCredential getCredential() {
+ return null;
+ }
+
+ @Override
+ public String getToken() {
+ return "mock-token";
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index a911bdb51..4b66e7f21 100644
--- a/pom.xml
+++ b/pom.xml
@@ -62,7 +62,8 @@
1.17.2
23.0.3
3.0.0
- 1.16.1
+ 1.16.1
+ 1.18.0
4.5.7
1.21.0
1.16