Skip to content

Commit 46100d8

Browse files
authored
Merge pull request #478 from deutschebank/spring-bot-master-db
certificate base authentication
2 parents 3795e30 + e6fbf47 commit 46100d8

File tree

10 files changed

+121
-24
lines changed

10 files changed

+121
-24
lines changed

libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/TeamsWorkflowConfig.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
6262
import com.microsoft.bot.builder.TurnContext;
6363
import com.microsoft.bot.builder.teams.TeamsActivityHandler;
64+
import com.microsoft.bot.connector.teams.TeamsConnectorClient;
6465
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
6566
import com.microsoft.bot.schema.ChannelAccount;
6667

@@ -230,8 +231,9 @@ public TeamsActivityHandler teamsActivityHandler(
230231
FormValidationProcessor fvp,
231232
TeamsConversations tc,
232233
TeamsStateStorage teamsStateStorage,
233-
TeamsFormConverter fc) {
234-
return new FileActivityHandler(messageConsumers, tc, teamsStateStorage, parser, fc, fvp);
234+
TeamsFormConverter fc,
235+
TeamsConnectorClient teamsConnectorClient) {
236+
return new FileActivityHandler(messageConsumers, tc, teamsStateStorage, parser, fc, fvp, teamsConnectorClient);
235237
}
236238

237239
@Bean

libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/AbstractTeamsConversations.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,9 +219,9 @@ private TurnContext getWorkingTurnContext(TeamsAddressable ta) {
219219
try {
220220
TurnContext out = CurrentTurnContext.CURRENT_CONTEXT.get();
221221

222-
if (out != null) {
223-
return out;
224-
}
222+
// if (out != null) {
223+
// return out;
224+
// }
225225

226226
TurnContext[] holder = new TurnContext[1];
227227

libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotAppCredentials.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.finos.springbot.teams.conversations;
22

33
import com.azure.identity.ClientCertificateCredential;
4+
import com.microsoft.bot.connector.authentication.CertificateAppCredentials;
45

56
public interface SpringBotAppCredentials {
67

@@ -12,4 +13,6 @@ public interface SpringBotAppCredentials {
1213

1314
String getToken();
1415

16+
CertificateAppCredentials getAppCredentials();
17+
1518
}

libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/SpringBotMicrosoftAppCredentials.java

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,26 @@
33
import java.io.IOException;
44
import java.nio.file.Files;
55
import java.nio.file.Paths;
6+
import java.security.KeyStoreException;
7+
import java.security.NoSuchAlgorithmException;
8+
import java.security.NoSuchProviderException;
9+
import java.security.UnrecoverableKeyException;
10+
import java.security.cert.CertificateException;
611
import java.util.Base64;
712

813
import com.azure.core.credential.TokenRequestContext;
914
import com.azure.identity.ClientCertificateCredential;
1015
import com.azure.identity.ClientCertificateCredentialBuilder;
16+
import com.microsoft.bot.connector.authentication.CertificateAppCredentials;
17+
import com.microsoft.bot.connector.authentication.CertificateAppCredentialsOptions;
1118

1219
public class SpringBotMicrosoftAppCredentials implements SpringBotAppCredentials {
1320

1421
private String tenantId = null;
1522
private String clientId = null;
1623
private ClientCertificateCredential credential = null;
17-
24+
private CertificateAppCredentials appCredentials = null;
25+
1826
public SpringBotMicrosoftAppCredentials(String tenantId, String clientId, String certificate,
1927
String certificatePassword) {
2028
this.tenantId = tenantId;
@@ -37,14 +45,21 @@ public SpringBotMicrosoftAppCredentials(String tenantId, String clientId, String
3745
this.credential = new ClientCertificateCredentialBuilder().tenantId(tenantId).clientId(clientId)
3846
.pemCertificate(Files.newInputStream(Paths.get(certificate)))
3947
.clientCertificatePassword(certificatePassword).build();
48+
49+
CertificateAppCredentialsOptions out = new CertificateAppCredentialsOptions(clientId,
50+
Files.newInputStream(Paths.get(certificate)), certificatePassword);
51+
52+
appCredentials = new CertificateAppCredentials(out);
53+
4054
}
41-
} catch (IOException e) {
55+
} catch (IOException | UnrecoverableKeyException | CertificateException | NoSuchAlgorithmException
56+
| KeyStoreException | NoSuchProviderException e) {
4257
e.printStackTrace();
4358
throw new RuntimeException("Failed to create certificate", e);
4459
}
4560

4661
}
47-
62+
4863
@Override
4964
public String getTenantId() {
5065
return tenantId;
@@ -61,10 +76,22 @@ public ClientCertificateCredential getCredential() {
6176
}
6277

6378
@Override
64-
public String getToken() {
65-
return credential.getTokenSync(new TokenRequestContext().addScopes("https://graph.microsoft.com/.default"))
66-
.getToken();
79+
public CertificateAppCredentials getAppCredentials() {
80+
return appCredentials;
6781
}
68-
82+
83+
84+
@Override
85+
public String getToken() {
86+
87+
String token = credential.getTokenSync(
88+
new TokenRequestContext().addScopes("https://api.botframework.com/.default")
89+
).getToken();
90+
91+
return token;
92+
93+
}
6994

95+
96+
7097
}

libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/conversations/TeamsConversationsConfig.java

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@
99
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
1010
import org.springframework.context.ApplicationContext;
1111
import org.springframework.context.annotation.Bean;
12+
import org.springframework.context.annotation.Primary;
1213

1314
import com.microsoft.bot.builder.BotFrameworkAdapter;
15+
import com.microsoft.bot.connector.authentication.AuthenticationConfiguration;
16+
import com.microsoft.bot.connector.authentication.CertificateAppCredentials;
17+
import com.microsoft.bot.connector.authentication.ChannelProvider;
18+
import com.microsoft.bot.connector.rest.RestTeamsConnectorClient;
19+
import com.microsoft.bot.connector.teams.TeamsConnectorClient;
1420
import com.microsoft.bot.integration.AdapterWithErrorHandler;
1521
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
22+
import com.microsoft.bot.integration.Configuration;
1623
import com.microsoft.bot.schema.ChannelAccount;
1724

1825
public class TeamsConversationsConfig extends BotDependencyConfiguration {
1926

2027
@Bean
21-
public SpringBotAppCredentials microsoftCredentials(@Value("${teams.app.tennantId}") String tennantId) {
28+
public SpringBotAppCredentials springBotAppCredentials(@Value("${teams.app.tennantId}") String tennantId) {
2229
com.microsoft.bot.integration.Configuration conf = getConfiguration();
2330

2431
String clientId = conf
@@ -27,15 +34,42 @@ public SpringBotAppCredentials microsoftCredentials(@Value("${teams.app.tennantI
2734
SpringBotAppCredentials out = new SpringBotMicrosoftAppCredentials(tennantId,
2835
clientId, conf.getProperty("MicrosoftAppIdPemCertificate"),
2936
conf.getProperty("MicrosoftAppIdPemCertificatePassword"));
30-
31-
// MicrosoftAppCredentials mac = new MicrosoftAppCredentials(
32-
// conf.getProperty(MicrosoftAppCredentials.MICROSOFTAPPID),
33-
// conf.getProperty(MicrosoftAppCredentials.MICROSOFTAPPPASSWORD),
34-
// tennantId);
35-
3637
return out;
3738
}
38-
39+
40+
@Primary
41+
@Bean
42+
public CertificateAppCredentials certificateCredentials(SpringBotAppCredentials credentials) {
43+
return credentials.getAppCredentials();
44+
}
45+
46+
@Bean
47+
public TeamsConnectorClient restTeamsConnectorClient(CertificateAppCredentials credentials) {
48+
return new RestTeamsConnectorClient("https://smba.trafficmanager.net/uk/", credentials);
49+
}
50+
51+
@Primary
52+
@Bean
53+
public BotFrameworkAdapter botFrameworkAdapter(
54+
CertificateAppCredentials withCredentials,
55+
AuthenticationConfiguration withAuthConfig,
56+
ChannelProvider withChannelProvider) {
57+
58+
Configuration conf = getConfiguration();
59+
60+
String clientId = conf.getProperty("MicrosoftAppId");
61+
withCredentials.setAppId(clientId);
62+
63+
BotFrameworkAdapter adapter = new BotFrameworkAdapter(withCredentials,
64+
withAuthConfig,
65+
withChannelProvider,
66+
null,
67+
null);
68+
69+
return adapter;
70+
}
71+
72+
3973
@Bean
4074
@ConditionalOnMissingBean
4175
public TeamsConversations teamsConversations(

libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/messages/FileActivityHandler.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import com.microsoft.bot.builder.MessageFactory;
2626
import com.microsoft.bot.builder.TurnContext;
27+
import com.microsoft.bot.connector.teams.TeamsConnectorClient;
2728
import com.microsoft.bot.schema.Activity;
2829
import com.microsoft.bot.schema.Attachment;
2930
import com.microsoft.bot.schema.ResultPair;
@@ -38,8 +39,9 @@ public class FileActivityHandler extends MessageActivityHandler {
3839

3940
public FileActivityHandler(List<ActionConsumer> messageConsumers, TeamsConversations teamsConversations,
4041
TeamsStateStorage teamsStateStorage, TeamsHTMLParser parser, FormConverter formConverter,
41-
FormValidationProcessor validationProcessor) {
42-
super(messageConsumers, teamsConversations, teamsStateStorage, parser, formConverter, validationProcessor);
42+
FormValidationProcessor validationProcessor, TeamsConnectorClient teamsConnectorClient) {
43+
super(messageConsumers, teamsConversations, teamsStateStorage, parser, formConverter, validationProcessor,
44+
teamsConnectorClient);
4345
}
4446

4547
@Override

libs/teams/teams-chat-workflow-spring-boot-starter/src/main/java/org/finos/springbot/teams/messages/MessageActivityHandler.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import org.slf4j.LoggerFactory;
2727
import org.springframework.http.MediaType;
2828

29+
import com.microsoft.bot.builder.BotFrameworkAdapter;
2930
import com.microsoft.bot.builder.TurnContext;
3031
import com.microsoft.bot.builder.teams.TeamsActivityHandler;
32+
import com.microsoft.bot.connector.teams.TeamsConnectorClient;
3133
import com.microsoft.bot.schema.Activity;
3234
import com.microsoft.bot.schema.Attachment;
3335

@@ -41,21 +43,24 @@ public class MessageActivityHandler extends TeamsActivityHandler {
4143
TeamsStateStorage teamsStateStorage;
4244
FormConverter formConverter;
4345
FormValidationProcessor validationProcessor;
46+
TeamsConnectorClient teamsConnectorClient;
4447

4548
public MessageActivityHandler(
4649
List<ActionConsumer> messageConsumers,
4750
TeamsConversations teamsConversations,
4851
TeamsStateStorage teamsStateStorage,
4952
TeamsHTMLParser parser,
5053
FormConverter formConverter,
51-
FormValidationProcessor validationProcessor) {
54+
FormValidationProcessor validationProcessor,
55+
TeamsConnectorClient teamsConnectorClient) {
5256
super();
5357
this.messageConsumers = messageConsumers;
5458
this.teamsConversations = teamsConversations;
5559
this.teamsStateStorage = teamsStateStorage;
5660
this.messageParser = parser;
5761
this.formConverter = formConverter;
5862
this.validationProcessor = validationProcessor;
63+
this.teamsConnectorClient = teamsConnectorClient;
5964
}
6065

6166
@Override
@@ -69,6 +74,11 @@ public void handleActivity(TurnContext turnContext) {
6974
Activity a = turnContext.getActivity();
7075

7176
try {
77+
78+
turnContext.getTurnState().remove(BotFrameworkAdapter.TEAMSCONNECTOR_CLIENT_KEY);
79+
turnContext.getTurnState().add(BotFrameworkAdapter.TEAMSCONNECTOR_CLIENT_KEY, teamsConnectorClient);
80+
81+
7282
CurrentTurnContext.CURRENT_CONTEXT.set(turnContext);
7383
Action action = (a.getValue() != null) ? processForm(turnContext, a) : processMessage(turnContext, a);
7484

libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/MockTeamsConfiguration.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import org.springframework.context.annotation.Primary;
99
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
1010

11+
import com.microsoft.bot.connector.authentication.CertificateAppCredentials;
12+
1113
@Configuration
1214
public class MockTeamsConfiguration {
1315

@@ -27,4 +29,9 @@ public SpringBotAppCredentials dummyMicrosoftCredentials() {
2729
return new MockSpringBotMicrosoftAppCredentials();
2830
}
2931

32+
@Bean
33+
public CertificateAppCredentials certificateAppCredentials(SpringBotAppCredentials appCredentials) {
34+
return appCredentials.getAppCredentials();
35+
}
36+
3037
}

libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/controller/TeamsHandlerMappingTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.fasterxml.jackson.databind.ObjectMapper;
4747
import com.fasterxml.jackson.databind.node.ObjectNode;
4848
import com.microsoft.bot.builder.TurnContext;
49+
import com.microsoft.bot.builder.TurnContextStateCollection;
4950
import com.microsoft.bot.schema.Activity;
5051
import com.microsoft.bot.schema.ActivityTypes;
5152
import com.microsoft.bot.schema.Attachment;
@@ -219,7 +220,10 @@ public static <R> CompletableFuture<R> failed(Throwable error) {
219220
private void mockTurnContext(String s, Map<String, Object> formData, boolean isAttachement) {
220221
tc = Mockito.mock(TurnContext.class);
221222
CurrentTurnContext.CURRENT_CONTEXT.set(tc);
222-
223+
224+
TurnContextStateCollection tcsc = Mockito.mock(TurnContextStateCollection.class);
225+
Mockito.when(tc.getTurnState()).thenReturn(tcsc);
226+
223227
msg = ArgumentCaptor.forClass(Activity.class);
224228
Mockito.when(tc.sendActivity(msg.capture())).thenReturn(CompletableFuture.completedFuture(null));
225229

libs/teams/teams-chat-workflow-spring-boot-starter/src/test/java/org/finos/springbot/teams/conversations/MockSpringBotMicrosoftAppCredentials.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package org.finos.springbot.teams.conversations;
22

3+
import org.mockito.Mockito;
4+
35
import com.azure.identity.ClientCertificateCredential;
6+
import com.microsoft.bot.connector.authentication.CertificateAppCredentials;
47

58
public class MockSpringBotMicrosoftAppCredentials implements SpringBotAppCredentials {
69

@@ -24,4 +27,9 @@ public String getToken() {
2427
return "mock-token";
2528
}
2629

30+
@Override
31+
public CertificateAppCredentials getAppCredentials() {
32+
return Mockito.mock(CertificateAppCredentials.class);
33+
}
34+
2735
}

0 commit comments

Comments
 (0)