diff --git a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotFrameworkAdapter.java b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotFrameworkAdapter.java index e8b309f5f..4500b90fb 100644 --- a/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotFrameworkAdapter.java +++ b/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/BotFrameworkAdapter.java @@ -49,6 +49,7 @@ import com.microsoft.bot.schema.TokenStatus; import com.microsoft.bot.restclient.retry.RetryStrategy; import java.util.Collections; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.lang3.StringUtils; import java.net.HttpURLConnection; @@ -1069,41 +1070,47 @@ public CompletableFuture createConversation(String channelId, String servi * If null, the default credentials will be used. * @return An OAuth client for the bot. */ - protected CompletableFuture createOAuthAPIClient(TurnContext turnContext, - AppCredentials oAuthAppCredentials) { + protected CompletableFuture createOAuthAPIClient( + TurnContext turnContext, + AppCredentials oAuthAppCredentials + ) { if (!OAuthClientConfig.emulateOAuthCards && StringUtils.equalsIgnoreCase(turnContext.getActivity().getChannelId(), Channels.EMULATOR) - && credentialProvider.isAuthenticationDisabled().join()) { + && credentialProvider.isAuthenticationDisabled().join() + ) { OAuthClientConfig.emulateOAuthCards = true; } + AtomicBoolean sendEmulateOAuthCards = new AtomicBoolean(false); String appId = getBotAppId(turnContext); String cacheKey = appId + (oAuthAppCredentials != null ? oAuthAppCredentials.getAppId() : ""); - String oAuthScope = getBotFrameworkOAuthScope(); - AppCredentials credentials = oAuthAppCredentials != null ? oAuthAppCredentials - : getAppCredentials(appId, oAuthScope).join(); OAuthClient client = oAuthClients.computeIfAbsent(cacheKey, key -> { - OAuthClient oAuthClient = new RestOAuthClient( - OAuthClientConfig.emulateOAuthCards ? turnContext.getActivity().getServiceUrl() - : OAuthClientConfig.OAUTHENDPOINT, - credentials); - - if (OAuthClientConfig.emulateOAuthCards) { - // do not join task - we want this to run in the background. - OAuthClientConfig.sendEmulateOAuthCards(oAuthClient, OAuthClientConfig.emulateOAuthCards); - } + sendEmulateOAuthCards.set(OAuthClientConfig.emulateOAuthCards); + + String oAuthScope = getBotFrameworkOAuthScope(); + AppCredentials credentials = oAuthAppCredentials != null + ? oAuthAppCredentials + : getAppCredentials(appId, oAuthScope).join(); - return oAuthClient; + return new RestOAuthClient( + OAuthClientConfig.emulateOAuthCards + ? turnContext.getActivity().getServiceUrl() + : OAuthClientConfig.OAUTHENDPOINT, + credentials + ); }); // adding the oAuthClient into the TurnState - // TokenResolver.cs will use it get the correct credentials to poll for - // token for streaming scenario if (turnContext.getTurnState().get(BotAdapter.OAUTH_CLIENT_KEY) == null) { turnContext.getTurnState().add(BotAdapter.OAUTH_CLIENT_KEY, client); } + if (sendEmulateOAuthCards.get()) { + return client.getUserToken().sendEmulateOAuthCards(true) + .thenApply(voidresult -> client); + } + return CompletableFuture.completedFuture(client); } diff --git a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/OAuthClientConfig.java b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/OAuthClientConfig.java index ae70776f2..e6dfc0d5e 100644 --- a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/OAuthClientConfig.java +++ b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/OAuthClientConfig.java @@ -4,9 +4,6 @@ package com.microsoft.bot.connector; import com.microsoft.bot.connector.authentication.AuthenticationConstants; -import org.apache.commons.lang3.NotImplementedException; - -import java.util.concurrent.CompletableFuture; /** * OAuthClient config. @@ -27,19 +24,4 @@ private OAuthClientConfig() { */ @SuppressWarnings("checkstyle:VisibilityModifier") public static boolean emulateOAuthCards = false; - - /** - * Send a dummy OAuth card when the bot is being used on the Emulator for - * testing without fetching a real token. - * - * @param client The OAuth client. - * @param emulate Indicates whether the Emulator should emulate the OAuth card. - * @return A task that represents the work queued to execute. - */ - public static CompletableFuture sendEmulateOAuthCards( - OAuthClient client, - boolean emulate - ) { - throw new NotImplementedException("sendEmulateOAuthCards"); - } } diff --git a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/UserToken.java b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/UserToken.java index 6422a030e..4b9686984 100644 --- a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/UserToken.java +++ b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/UserToken.java @@ -129,4 +129,12 @@ CompletableFuture> getTokenStatus( String channelId, String include ); + + /** + * Send a dummy OAuth card when the bot is being used on the Emulator for testing without fetching a real token. + * + * @param emulateOAuthCards Indicates whether the Emulator should emulate the OAuth card. + * @return A task that represents the work queued to execute. + */ + CompletableFuture sendEmulateOAuthCards(boolean emulateOAuthCards); } diff --git a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestUserToken.java b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestUserToken.java index bb7c7c27c..e7a42dbf0 100644 --- a/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestUserToken.java +++ b/libraries/bot-connector/src/main/java/com/microsoft/bot/connector/rest/RestUserToken.java @@ -112,6 +112,13 @@ CompletableFuture> getTokenStatus( @Query("channelId") String channelId, @Query("include") String include ); + + @Headers({ "Content-Type: application/json; charset=utf-8", + "x-ms-logging-context: com.microsoft.bot.schema.UserTokens sendEmulateOAuthCards" }) + @POST("api/usertoken/emulateOAuthCards") + CompletableFuture> sendEmulateOAuthCards( + @Query("emulate") boolean emulate + ); } /** @@ -532,4 +539,39 @@ private ServiceResponse> getTokenStatusDelegate( .registerError(ErrorResponseException.class) .build(response); } + + /** + * Send a dummy OAuth card when the bot is being used on the Emulator for testing without fetching a real token. + * + * @param emulateOAuthCards Indicates whether the Emulator should emulate the OAuth card. + * @return A task that represents the work queued to execute. + */ + @Override + public CompletableFuture sendEmulateOAuthCards(boolean emulateOAuthCards) { + return service.sendEmulateOAuthCards(emulateOAuthCards) + .thenApply(responseBodyResponse -> { + try { + return sendEmulateOAuthCardsDelegate(responseBodyResponse).body(); + } catch (ErrorResponseException e) { + throw e; + } catch (Throwable t) { + throw new ErrorResponseException("sendEmulateOAuthCards", responseBodyResponse); + } + }); + } + + private ServiceResponse sendEmulateOAuthCardsDelegate( + Response response + ) throws ErrorResponseException, IOException, IllegalArgumentException { + + return client.restClient() + .responseBuilderFactory() + .newInstance(client.serializerAdapter()) + .register(HttpURLConnection.HTTP_OK, new TypeToken() { + }.getType()) + .register(HttpURLConnection.HTTP_ACCEPTED, new TypeToken() { + }.getType()) + .registerError(ErrorResponseException.class) + .build(response); + } }