Move allowed callers and skill conversation factory to SDK (#1062)
* Move allowed callers and skill convo factory * Update for Application file. Co-authored-by: tracyboehrer <tracyboehrer@users.noreply.github.com>
This commit is contained in:
Родитель
466fd90b80
Коммит
837dca217f
|
@ -1,16 +1,13 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.sample.dialogrootbot;
|
||||
package com.microsoft.bot.builder.skills;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.microsoft.bot.builder.Storage;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactoryBase;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactoryOptions;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationReference;
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import com.microsoft.bot.schema.ConversationReference;
|
||||
|
||||
|
@ -25,6 +22,11 @@ public class SkillConversationIdFactory extends SkillConversationIdFactoryBase {
|
|||
|
||||
private Storage storage;
|
||||
|
||||
/**
|
||||
* Creates an instance of a SkillConversationIdFactory.
|
||||
*
|
||||
* @param storage A storage instance for the factory.
|
||||
*/
|
||||
public SkillConversationIdFactory(Storage storage) {
|
||||
if (storage == null) {
|
||||
throw new IllegalArgumentException("Storage cannot be null.");
|
||||
|
@ -32,18 +34,26 @@ public class SkillConversationIdFactory extends SkillConversationIdFactoryBase {
|
|||
this.storage = storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a conversation id for a skill conversation.
|
||||
*
|
||||
* @param options A {@link SkillConversationIdFactoryOptions} instance
|
||||
* containing parameters for creating the conversation ID.
|
||||
*
|
||||
* @return A unique conversation ID used to communicate with the skill.
|
||||
*
|
||||
* It should be possible to use the returned String on a request URL and
|
||||
* it should not contain special characters.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<String> createSkillConversationId(SkillConversationIdFactoryOptions options) {
|
||||
if (options == null) {
|
||||
Async.completeExceptionally(new IllegalArgumentException("options cannot be null."));
|
||||
}
|
||||
ConversationReference conversationReference = options.getActivity().getConversationReference();
|
||||
String skillConversationId = String.format(
|
||||
"%s-%s-%s-skillconvo",
|
||||
conversationReference.getConversation().getId(),
|
||||
options.getBotFrameworkSkill().getId(),
|
||||
conversationReference.getChannelId()
|
||||
);
|
||||
String skillConversationId = String.format("%s-%s-%s-skillconvo",
|
||||
conversationReference.getConversation().getId(), options.getBotFrameworkSkill().getId(),
|
||||
conversationReference.getChannelId());
|
||||
|
||||
SkillConversationReference skillConversationReference = new SkillConversationReference();
|
||||
skillConversationReference.setConversationReference(conversationReference);
|
||||
|
@ -51,9 +61,20 @@ public class SkillConversationIdFactory extends SkillConversationIdFactoryBase {
|
|||
Map<String, Object> skillConversationInfo = new HashMap<String, Object>();
|
||||
skillConversationInfo.put(skillConversationId, skillConversationReference);
|
||||
return storage.write(skillConversationInfo)
|
||||
.thenCompose(result -> CompletableFuture.completedFuture(skillConversationId));
|
||||
.thenCompose(result -> CompletableFuture.completedFuture(skillConversationId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link SkillConversationReference} created using
|
||||
* {@link SkillConversationIdFactory#createSkillConversationId} for a
|
||||
* skillConversationId.
|
||||
*
|
||||
* @param skillConversationId A skill conversationId created using
|
||||
* {@link SkillConversationIdFactory#createSkillConversationId}.
|
||||
*
|
||||
* @return The caller's {@link ConversationReference} for a skillConversationId.
|
||||
* null if not found.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<SkillConversationReference> getSkillConversationReference(String skillConversationId) {
|
||||
if (StringUtils.isAllBlank(skillConversationId)) {
|
||||
|
@ -63,13 +84,22 @@ public class SkillConversationIdFactory extends SkillConversationIdFactoryBase {
|
|||
return storage.read(new String[] {skillConversationId}).thenCompose(skillConversationInfo -> {
|
||||
if (skillConversationInfo.size() > 0) {
|
||||
return CompletableFuture
|
||||
.completedFuture((SkillConversationReference) skillConversationInfo.get(skillConversationId));
|
||||
.completedFuture((SkillConversationReference) skillConversationInfo.get(skillConversationId));
|
||||
} else {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a {@link ConversationReference} .
|
||||
*
|
||||
* @param skillConversationId A skill conversationId created using {@link
|
||||
* CreateSkillConversationId(SkillConversationIdFactoryOptions,System#getT
|
||||
* reading()#getCancellationToken())} .
|
||||
*
|
||||
* @return A {@link CompletableFuture} representing the asynchronous operation.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteConversationReference(String skillConversationId) {
|
||||
return storage.delete(new String[] {skillConversationId});
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.builder;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.microsoft.bot.builder.skills.BotFrameworkSkill;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactory;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactoryOptions;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationReference;
|
||||
import com.microsoft.bot.schema.Activity;
|
||||
import com.microsoft.bot.schema.ConversationAccount;
|
||||
import com.microsoft.bot.schema.ConversationReference;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Assert;
|
||||
|
||||
|
||||
public class SkillConversationIdFactoryTests {
|
||||
|
||||
private static final String SERVICE_URL = "http://testbot.com/api/messages";
|
||||
private final String skillId = "skill";
|
||||
|
||||
private final SkillConversationIdFactory skillConversationIdFactory =
|
||||
new SkillConversationIdFactory(new MemoryStorage());
|
||||
private final String applicationId = UUID.randomUUID().toString();
|
||||
private final String botId = UUID.randomUUID().toString();
|
||||
|
||||
@Test
|
||||
public void SkillConversationIdFactoryHappyPath() {
|
||||
ConversationReference conversationReference = buildConversationReference();
|
||||
|
||||
// Create skill conversation
|
||||
SkillConversationIdFactoryOptions options = new SkillConversationIdFactoryOptions();
|
||||
options.setActivity(buildMessageActivity(conversationReference));
|
||||
options.setBotFrameworkSkill(this.buildBotFrameworkSkill());
|
||||
options.setFromBotId(botId);
|
||||
options.setFromBotOAuthScope(botId);
|
||||
|
||||
|
||||
String skillConversationId = skillConversationIdFactory.createSkillConversationId(options).join();
|
||||
|
||||
Assert.assertFalse(StringUtils.isBlank(skillConversationId));
|
||||
|
||||
// Retrieve skill conversation
|
||||
SkillConversationReference retrievedConversationReference =
|
||||
skillConversationIdFactory.getSkillConversationReference(skillConversationId).join();
|
||||
|
||||
// Delete
|
||||
skillConversationIdFactory.deleteConversationReference(skillConversationId);
|
||||
|
||||
// Retrieve again
|
||||
SkillConversationReference deletedConversationReference =
|
||||
skillConversationIdFactory.getSkillConversationReference(skillConversationId).join();
|
||||
|
||||
Assert.assertNotNull(retrievedConversationReference);
|
||||
Assert.assertNotNull(retrievedConversationReference.getConversationReference());
|
||||
Assert.assertTrue(compareConversationReferences(conversationReference,
|
||||
retrievedConversationReference.getConversationReference()));
|
||||
Assert.assertNull(deletedConversationReference);
|
||||
}
|
||||
|
||||
private static ConversationReference buildConversationReference() {
|
||||
ConversationReference conversationReference = new ConversationReference();
|
||||
conversationReference.setConversation(new ConversationAccount(UUID.randomUUID().toString()));
|
||||
conversationReference.setServiceUrl(SERVICE_URL);
|
||||
return conversationReference;
|
||||
}
|
||||
|
||||
private static Activity buildMessageActivity(ConversationReference conversationReference) {
|
||||
if (conversationReference == null) {
|
||||
throw new IllegalArgumentException("conversationReference cannot be null.");
|
||||
}
|
||||
|
||||
Activity activity = Activity.createMessageActivity();
|
||||
activity.applyConversationReference(conversationReference);
|
||||
|
||||
return activity;
|
||||
}
|
||||
|
||||
private BotFrameworkSkill buildBotFrameworkSkill() {
|
||||
BotFrameworkSkill skill = new BotFrameworkSkill();
|
||||
skill.setAppId(applicationId);
|
||||
skill.setId(skillId);
|
||||
try {
|
||||
skill.setSkillEndpoint(new URI(SERVICE_URL));
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return skill;
|
||||
}
|
||||
|
||||
private static boolean compareConversationReferences(
|
||||
ConversationReference reference1,
|
||||
ConversationReference reference2
|
||||
) {
|
||||
return reference1.getConversation().getId() == reference2.getConversation().getId()
|
||||
&& reference1.getServiceUrl() == reference2.getServiceUrl();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.connector.authentication;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.microsoft.bot.connector.Async;
|
||||
|
||||
/**
|
||||
* Sample claims validator that loads an allowed list from configuration if
|
||||
* presentand checks that requests are coming from allowed parent bots.
|
||||
*/
|
||||
public class AllowedCallersClaimsValidator extends ClaimsValidator {
|
||||
|
||||
private List<String> allowedCallers;
|
||||
|
||||
/**
|
||||
* Creates an instance of an {@link AllowedCallersClaimsValidator}.
|
||||
* @param withAllowedCallers A List<String> that contains the list of allowed callers.
|
||||
*/
|
||||
public AllowedCallersClaimsValidator(List<String> withAllowedCallers) {
|
||||
this.allowedCallers = withAllowedCallers != null ? withAllowedCallers : new ArrayList<String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a Map of claims and should throw an exception if the
|
||||
* validation fails.
|
||||
*
|
||||
* @param claims The Map of claims to validate.
|
||||
*
|
||||
* @return true if the validation is successful, false if not.
|
||||
*/
|
||||
@Override
|
||||
public CompletableFuture<Void> validateClaims(Map<String, String> claims) {
|
||||
if (claims == null) {
|
||||
return Async.completeExceptionally(new IllegalArgumentException("Claims cannot be null"));
|
||||
}
|
||||
|
||||
// If _allowedCallers contains an "*", we allow all callers.
|
||||
if (SkillValidation.isSkillClaim(claims) && !allowedCallers.contains("*")) {
|
||||
// Check that the appId claim in the skill request instanceof in the list of
|
||||
// callers configured for this bot.
|
||||
String appId = JwtTokenValidation.getAppIdFromClaims(claims);
|
||||
if (!allowedCallers.contains(appId)) {
|
||||
return Async.completeExceptionally(
|
||||
new RuntimeException(
|
||||
String.format(
|
||||
"Received a request from a bot with an app ID of \"%s\". To enable requests from this "
|
||||
+ "caller, add the app ID to the configured set of allowedCallers.",
|
||||
appId
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.connector;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.microsoft.bot.connector.authentication.AllowedCallersClaimsValidator;
|
||||
import com.microsoft.bot.connector.authentication.AuthenticationConstants;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AllowedCallersClaimsValidationTests {
|
||||
|
||||
private final String version = "1.0";
|
||||
|
||||
private final String audienceClaim = UUID.randomUUID().toString();
|
||||
|
||||
public static List<Pair<String, List<String>>> getConfigureServicesSucceedsData() {
|
||||
String primaryAppId = UUID.randomUUID().toString();
|
||||
String secondaryAppId = UUID.randomUUID().toString();
|
||||
|
||||
List<Pair<String, List<String>>> resultList = new ArrayList<Pair<String, List<String>>>();
|
||||
// Null allowed callers
|
||||
resultList.add(Pair.of(null, null));
|
||||
// Null configuration with attempted caller
|
||||
resultList.add(Pair.of(primaryAppId, null));
|
||||
// Empty allowed callers array
|
||||
resultList.add(Pair.of(null, new ArrayList<String>()));
|
||||
// Allow any caller
|
||||
resultList.add(Pair.of(primaryAppId, new ArrayList<String>() { { add("*"); } }));
|
||||
// Specify allowed caller
|
||||
resultList.add((Pair.of(primaryAppId, new ArrayList<String>() { { add(primaryAppId); } })));
|
||||
// Specify multiple callers
|
||||
resultList.add((Pair.of(primaryAppId, new ArrayList<String>() { { add(primaryAppId);
|
||||
add(secondaryAppId); } })));
|
||||
// Blocked caller throws exception
|
||||
resultList.add((Pair.of(primaryAppId, new ArrayList<String>() { { add(secondaryAppId); } })));
|
||||
return resultList;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TestAcceptAllowedCallersArray() {
|
||||
List<Pair<String, List<String>>> configuredServices = getConfigureServicesSucceedsData();
|
||||
for (Pair<String, List<String>> item : configuredServices) {
|
||||
acceptAllowedCallersArray(item.getLeft(), item.getRight());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void acceptAllowedCallersArray(String allowedCallerClaimId, List<String> allowList) {
|
||||
AllowedCallersClaimsValidator validator = new AllowedCallersClaimsValidator(allowList);
|
||||
|
||||
if (allowedCallerClaimId != null) {
|
||||
Map<String, String> claims = createCallerClaims(allowedCallerClaimId);
|
||||
|
||||
if (allowList != null) {
|
||||
if (allowList.contains(allowedCallerClaimId) || allowList.contains("*")) {
|
||||
validator.validateClaims(claims);
|
||||
} else {
|
||||
validateUnauthorizedAccessException(allowedCallerClaimId, validator, claims);
|
||||
}
|
||||
} else {
|
||||
validateUnauthorizedAccessException(allowedCallerClaimId, validator, claims);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateUnauthorizedAccessException(
|
||||
String allowedCallerClaimId,
|
||||
AllowedCallersClaimsValidator validator,
|
||||
Map<String, String> claims) {
|
||||
try {
|
||||
validator.validateClaims(claims);
|
||||
} catch (RuntimeException exception) {
|
||||
Assert.assertTrue(exception.getMessage().contains(allowedCallerClaimId));
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> createCallerClaims(String appId) {
|
||||
Map<String, String> callerClaimMap = new HashMap<String, String>();
|
||||
|
||||
callerClaimMap.put(AuthenticationConstants.APPID_CLAIM, appId);
|
||||
callerClaimMap.put(AuthenticationConstants.VERSION_CLAIM, version);
|
||||
callerClaimMap.put(AuthenticationConstants.AUDIENCE_CLAIM, audienceClaim);
|
||||
return callerClaimMap;
|
||||
}
|
||||
}
|
||||
|
|
@ -84,6 +84,12 @@
|
|||
<version>4.6.0-preview9</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.bot</groupId>
|
||||
<artifactId>bot-builder</artifactId>
|
||||
<version>4.6.0-preview9</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.microsoft.bot.builder.BotAdapter;
|
|||
import com.microsoft.bot.builder.ChannelServiceHandler;
|
||||
import com.microsoft.bot.builder.ConversationState;
|
||||
import com.microsoft.bot.builder.MemoryStorage;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactory;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactoryBase;
|
||||
import com.microsoft.bot.builder.skills.SkillHandler;
|
||||
import com.microsoft.bot.connector.authentication.AuthenticationConfiguration;
|
||||
|
@ -110,7 +111,7 @@ public class Application extends BotDependencyConfiguration {
|
|||
|
||||
@Bean
|
||||
public SkillConversationIdFactoryBase getSkillConversationIdFactoryBase() {
|
||||
return new SkillConversationIdFactory();
|
||||
return new SkillConversationIdFactory(getStorage());
|
||||
}
|
||||
|
||||
@Bean public ChannelServiceHandler getChannelServiceHandler(
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.sample.simplerootbot;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactoryBase;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactoryOptions;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationReference;
|
||||
|
||||
/**
|
||||
* A {@link SkillConversationIdFactory} that uses an in memory
|
||||
* {@link Map{TKey,TValue}} to store and retrieve {@link ConversationReference}
|
||||
* instances.
|
||||
*/
|
||||
public class SkillConversationIdFactory extends SkillConversationIdFactoryBase {
|
||||
|
||||
private final Map<String, SkillConversationReference> _conversationRefs =
|
||||
new HashMap<String, SkillConversationReference>();
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> createSkillConversationId(SkillConversationIdFactoryOptions options) {
|
||||
SkillConversationReference skillConversationReference = new SkillConversationReference();
|
||||
skillConversationReference.setConversationReference(options.getActivity().getConversationReference());
|
||||
skillConversationReference.setOAuthScope(options.getFromBotOAuthScope());
|
||||
String key = String.format(
|
||||
"%s-%s-%s-%s-skillconvo",
|
||||
options.getFromBotId(),
|
||||
options.getBotFrameworkSkill().getAppId(),
|
||||
skillConversationReference.getConversationReference().getConversation().getId(),
|
||||
skillConversationReference.getConversationReference().getChannelId()
|
||||
);
|
||||
_conversationRefs.put(key, skillConversationReference);
|
||||
return CompletableFuture.completedFuture(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<SkillConversationReference> getSkillConversationReference(String skillConversationId) {
|
||||
SkillConversationReference conversationReference = _conversationRefs.get(skillConversationId);
|
||||
return CompletableFuture.completedFuture(conversationReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> deleteConversationReference(String skillConversationId) {
|
||||
_conversationRefs.remove(skillConversationId);
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
|
@ -3,13 +3,15 @@
|
|||
|
||||
package com.microsoft.bot.sample.echoskillbot;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.microsoft.bot.builder.Bot;
|
||||
import com.microsoft.bot.connector.authentication.AllowedCallersClaimsValidator;
|
||||
import com.microsoft.bot.connector.authentication.AuthenticationConfiguration;
|
||||
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
|
||||
import com.microsoft.bot.integration.Configuration;
|
||||
import com.microsoft.bot.integration.spring.BotController;
|
||||
import com.microsoft.bot.integration.spring.BotDependencyConfiguration;
|
||||
import com.microsoft.bot.sample.echoskillbot.authentication.AllowedCallersClaimsValidator;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
@ -35,6 +37,8 @@ import org.springframework.context.annotation.Import;
|
|||
*/
|
||||
public class Application extends BotDependencyConfiguration {
|
||||
|
||||
private final String configKey = "AllowedCallers";
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
@ -57,7 +61,9 @@ public class Application extends BotDependencyConfiguration {
|
|||
@Override
|
||||
public AuthenticationConfiguration getAuthenticationConfiguration(Configuration configuration) {
|
||||
AuthenticationConfiguration authenticationConfiguration = new AuthenticationConfiguration();
|
||||
authenticationConfiguration.setClaimsValidator(new AllowedCallersClaimsValidator(configuration));
|
||||
authenticationConfiguration.setClaimsValidator(
|
||||
new AllowedCallersClaimsValidator(Arrays.asList(configuration.getProperties(configKey)))
|
||||
);
|
||||
return authenticationConfiguration;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.sample.echoskillbot.authentication;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import com.microsoft.bot.connector.authentication.ClaimsValidator;
|
||||
import com.microsoft.bot.connector.authentication.JwtTokenValidation;
|
||||
import com.microsoft.bot.connector.authentication.SkillValidation;
|
||||
import com.microsoft.bot.integration.Configuration;
|
||||
|
||||
/**
|
||||
* Sample claims validator that loads an allowed list from configuration if
|
||||
* presentand checks that requests are coming from allowed parent bots.
|
||||
*/
|
||||
public class AllowedCallersClaimsValidator extends ClaimsValidator {
|
||||
|
||||
private final String configKey = "AllowedCallers";
|
||||
private final List<String> allowedCallers;
|
||||
|
||||
public AllowedCallersClaimsValidator(Configuration config) {
|
||||
if (config == null) {
|
||||
throw new IllegalArgumentException("config cannot be null.");
|
||||
}
|
||||
|
||||
// AllowedCallers instanceof the setting in the application.properties file
|
||||
// that consists of the list of parent bot Ds that are allowed to access the
|
||||
// skill.
|
||||
// To add a new parent bot, simply edit the AllowedCallers and add
|
||||
// the parent bot's Microsoft app ID to the list.
|
||||
// In this sample, we allow all callers if AllowedCallers contains an "*".
|
||||
String[] appsList = config.getProperties(configKey);
|
||||
if (appsList == null) {
|
||||
throw new IllegalStateException(String.format("\"%s\" not found in configuration.", configKey));
|
||||
}
|
||||
|
||||
allowedCallers = Arrays.asList(appsList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> validateClaims(Map<String, String> claims) {
|
||||
// If _allowedCallers contains an "*", we allow all callers.
|
||||
if (SkillValidation.isSkillClaim(claims) && !allowedCallers.contains("*")) {
|
||||
// Check that the appId claim in the skill request instanceof in the list of
|
||||
// callers configured for this bot.
|
||||
String appId = JwtTokenValidation.getAppIdFromClaims(claims);
|
||||
if (!allowedCallers.contains(appId)) {
|
||||
return Async.completeExceptionally(
|
||||
new RuntimeException(
|
||||
String.format(
|
||||
"Received a request from a bot with an app ID of \"%s\". "
|
||||
+ "To enable requests from this caller, add the app ID to your configuration file.",
|
||||
appId
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import com.microsoft.bot.builder.BotAdapter;
|
|||
import com.microsoft.bot.builder.ChannelServiceHandler;
|
||||
import com.microsoft.bot.builder.ConversationState;
|
||||
import com.microsoft.bot.builder.Storage;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactory;
|
||||
import com.microsoft.bot.builder.skills.SkillConversationIdFactoryBase;
|
||||
import com.microsoft.bot.builder.skills.SkillHandler;
|
||||
import com.microsoft.bot.connector.authentication.AuthenticationConfiguration;
|
||||
|
@ -18,8 +19,8 @@ import com.microsoft.bot.integration.Configuration;
|
|||
import com.microsoft.bot.integration.SkillHttpClient;
|
||||
import com.microsoft.bot.integration.spring.BotController;
|
||||
import com.microsoft.bot.integration.spring.BotDependencyConfiguration;
|
||||
import com.microsoft.bot.sample.dialogrootbot.Bots.RootBot;
|
||||
import com.microsoft.bot.sample.dialogrootbot.authentication.AllowedSkillsClaimsValidator;
|
||||
import com.microsoft.bot.sample.dialogrootbot.bots.RootBot;
|
||||
import com.microsoft.bot.sample.dialogrootbot.dialogs.MainDialog;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.sample.dialogrootbot.Bots;
|
||||
package com.microsoft.bot.sample.dialogrootbot.bots;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
|
||||
package com.microsoft.bot.sample.dialogskillbot;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.microsoft.bot.builder.Bot;
|
||||
import com.microsoft.bot.builder.ConversationState;
|
||||
import com.microsoft.bot.connector.authentication.AllowedCallersClaimsValidator;
|
||||
import com.microsoft.bot.connector.authentication.AuthenticationConfiguration;
|
||||
import com.microsoft.bot.integration.BotFrameworkHttpAdapter;
|
||||
import com.microsoft.bot.integration.Configuration;
|
||||
import com.microsoft.bot.integration.spring.BotController;
|
||||
import com.microsoft.bot.integration.spring.BotDependencyConfiguration;
|
||||
import com.microsoft.bot.sample.dialogskillbot.authentication.AllowedCallersClaimsValidator;
|
||||
import com.microsoft.bot.sample.dialogskillbot.bots.SkillBot;
|
||||
import com.microsoft.bot.sample.dialogskillbot.dialogs.ActivityRouterDialog;
|
||||
import com.microsoft.bot.sample.dialogskillbot.dialogs.DialogSkillBotRecognizer;
|
||||
|
@ -39,6 +41,8 @@ import org.springframework.context.annotation.Import;
|
|||
*/
|
||||
public class Application extends BotDependencyConfiguration {
|
||||
|
||||
private final String configKey = "AllowedCallers";
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
@ -65,7 +69,9 @@ public class Application extends BotDependencyConfiguration {
|
|||
@Override
|
||||
public AuthenticationConfiguration getAuthenticationConfiguration(Configuration configuration) {
|
||||
AuthenticationConfiguration authenticationConfiguration = new AuthenticationConfiguration();
|
||||
authenticationConfiguration.setClaimsValidator(new AllowedCallersClaimsValidator(configuration));
|
||||
authenticationConfiguration.setClaimsValidator(
|
||||
new AllowedCallersClaimsValidator(Arrays.asList(configuration.getProperties(configKey)))
|
||||
);
|
||||
return authenticationConfiguration;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MT License.
|
||||
|
||||
package com.microsoft.bot.sample.dialogskillbot.authentication;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.microsoft.bot.connector.Async;
|
||||
import com.microsoft.bot.connector.authentication.ClaimsValidator;
|
||||
import com.microsoft.bot.connector.authentication.JwtTokenValidation;
|
||||
import com.microsoft.bot.connector.authentication.SkillValidation;
|
||||
import com.microsoft.bot.integration.Configuration;
|
||||
|
||||
/**
|
||||
* Sample claims validator that loads an allowed list from configuration if
|
||||
* presentand checks that requests are coming from allowed parent bots.
|
||||
*/
|
||||
public class AllowedCallersClaimsValidator extends ClaimsValidator {
|
||||
|
||||
private final String configKey = "AllowedCallers";
|
||||
private final List<String> allowedCallers;
|
||||
|
||||
public AllowedCallersClaimsValidator(Configuration config) {
|
||||
if (config == null) {
|
||||
throw new IllegalArgumentException("config cannot be null.");
|
||||
}
|
||||
|
||||
// AllowedCallers instanceof the setting in the application.properties file
|
||||
// that consists of the list of parent bot Ds that are allowed to access the
|
||||
// skill.
|
||||
// To add a new parent bot, simply edit the AllowedCallers and add
|
||||
// the parent bot's Microsoft app ID to the list.
|
||||
// In this sample, we allow all callers if AllowedCallers contains an "*".
|
||||
String[] appsList = config.getProperties(configKey);
|
||||
if (appsList == null) {
|
||||
throw new IllegalStateException(String.format("\"%s\" not found in configuration.", configKey));
|
||||
}
|
||||
|
||||
allowedCallers = Arrays.asList(appsList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> validateClaims(Map<String, String> claims) {
|
||||
// If _allowedCallers contains an "*", we allow all callers.
|
||||
if (SkillValidation.isSkillClaim(claims) && !allowedCallers.contains("*")) {
|
||||
// Check that the appId claim in the skill request instanceof in the list of
|
||||
// callers configured for this bot.
|
||||
String appId = JwtTokenValidation.getAppIdFromClaims(claims);
|
||||
if (!allowedCallers.contains(appId)) {
|
||||
return Async.completeExceptionally(
|
||||
new RuntimeException(
|
||||
String.format(
|
||||
"Received a request from a bot with an app ID of \"%s\". "
|
||||
+ "To enable requests from this caller, add the app ID to your configuration file.",
|
||||
appId
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче