Support passing sas token url's for token service (#6449)

Co-authored-by: Swagat Mishra <swagatm@microsoft.com>
This commit is contained in:
swagat mishra 2022-08-24 10:26:14 -07:00 коммит произвёл GitHub
Родитель bc5d708320
Коммит fe6f8489d0
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 131 добавлений и 10 удалений

Просмотреть файл

@ -177,6 +177,7 @@ namespace Microsoft.Bot.Builder.Dialogs
},
},
TokenExchangeResource = signInResource.TokenExchangeResource,
TokenPostResource = signInResource.TokenPostResource
},
});
}

Просмотреть файл

@ -810,7 +810,7 @@ namespace Microsoft.Bot.Builder.Adapters
/// <param name="finalRedirect">A final redirect URL.</param>
/// <param name="cancellationToken">The cancellationToken.</param>
/// <returns>A SignInResource with the link and token exchange info.</returns>
public Task<SignInResource> GetSignInResourceAsync(ITurnContext turnContext, AppCredentials oAuthAppCredentials, string connectionName, string userId, string finalRedirect = null, CancellationToken cancellationToken = default)
public virtual Task<SignInResource> GetSignInResourceAsync(ITurnContext turnContext, AppCredentials oAuthAppCredentials, string connectionName, string userId, string finalRedirect = null, CancellationToken cancellationToken = default)
{
return Task.FromResult(new SignInResource()
{

Просмотреть файл

@ -57,6 +57,13 @@ namespace Microsoft.Bot.Schema
[JsonProperty(PropertyName = "tokenExchangeResource")]
public TokenExchangeResource TokenExchangeResource { get; set; }
/// <summary>
/// Gets or sets the resource to directly post a token to token service.
/// </summary>
/// <value>The resource to directly post a token to token service.</value>
[JsonProperty(PropertyName = "tokenPostResource")]
public TokenPostResource TokenPostResource { get; set; }
/// <summary>
/// Gets or sets action to use to perform signin.
/// </summary>

Просмотреть файл

@ -44,6 +44,13 @@ namespace Microsoft.Bot.Schema
[JsonProperty(PropertyName = "tokenExchangeResource")]
public TokenExchangeResource TokenExchangeResource { get; set; }
/// <summary>
/// Gets or sets additional properties that can be used for direct token posting operations.
/// </summary>
/// <value>The additional properties can be used for token posting operations.</value>
[JsonProperty(PropertyName = "tokenPostResource")]
public TokenPostResource TokenPostResource { get; set; }
/// <summary>
/// An initialization method that performs custom operations like setting defaults.
/// </summary>

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace Microsoft.Bot.Schema
{
/// <summary>
/// Response schema sent back from Bot Framework Token Service required to initiate a user token direct post.
/// </summary>
public partial class TokenPostResource
{
/// <summary>
/// Initializes a new instance of the <see cref="TokenPostResource"/> class.
/// </summary>
public TokenPostResource()
{
CustomInit();
}
/// <summary>
/// Gets or sets the shared access signature url used to directly post a token to Bot Framework Token Service.
/// </summary>
/// <value>The URI.</value>
[JsonProperty(PropertyName = "sasUrl")]
#pragma warning disable CA1056 // Uri properties should not be strings
public string SasUrl { get; set; }
#pragma warning restore CA1056 // Uri properties should not be strings
partial void CustomInit();
}
}

Просмотреть файл

@ -6,7 +6,9 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Adapters;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Schema;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Xunit;
@ -15,14 +17,21 @@ using Xunit.Sdk;
namespace Microsoft.Bot.Builder.Dialogs.Tests
{
public class OAuthPromptTests
{
{
private const string UserId = "user-id";
private const string ConnectionName = "connection-name";
private const string ChannelId = "channel-id";
private const string MagicCode = "888999";
private const string Token = "token123";
private const string ExchangeToken = "exch123";
public static TheoryData<TestAdapter, bool> SasTestData =>
new TheoryData<TestAdapter, bool>
{
{ new TestAdapter(), false },
{ new SignInResourceAdapter(), true }
};
[Fact]
public void OAuthPromptWithEmptySettingsShouldFail()
{
@ -589,7 +598,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Tests
[InlineData(true, Channels.Msteams, true)] //Override: show link; ChannelRequiresSingInLink() returns true; Result: show link
public async Task OAuthPromptSignInLinkSettingsCases(bool? showSignInLinkValue, string channelId, bool shouldHaveSignInLink)
{
var oAuthPromptSettings = new OAuthPromptSettings();
var oAuthPromptSettings = new OAuthPromptSettings();
oAuthPromptSettings.ShowSignInLink = showSignInLinkValue;
var convoState = new ConversationState(new MemoryStorage());
@ -620,11 +629,11 @@ namespace Microsoft.Bot.Builder.Dialogs.Tests
};
await new TestFlow(adapter, botCallbackHandler)
.Send(initialActivity)
.AssertReply(activity =>
{
Assert.Single(((Activity)activity).Attachments);
Assert.Equal(OAuthCard.ContentType, ((Activity)activity).Attachments[0].ContentType);
var oAuthCard = (OAuthCard)((Activity)activity).Attachments[0].Content;
.AssertReply(activity =>
{
Assert.Single(((Activity)activity).Attachments);
Assert.Equal(OAuthCard.ContentType, ((Activity)activity).Attachments[0].ContentType);
var oAuthCard = (OAuthCard)((Activity)activity).Attachments[0].Content;
var cardAction = oAuthCard.Buttons[0];
Assert.Equal(shouldHaveSignInLink, cardAction.Value != null);
})
@ -710,6 +719,55 @@ namespace Microsoft.Bot.Builder.Dialogs.Tests
.StartTestAsync();
}
[Theory]
[MemberData(nameof(SasTestData))]
public async Task OAuthPromptSasUrlPresentInOAuthCard(TestAdapter testAdapter, bool containsSasurl)
{
var oAuthPromptSettings = new OAuthPromptSettings();
var convoState = new ConversationState(new MemoryStorage());
var dialogState = convoState.CreateProperty<DialogState>("dialogState");
var adapter = testAdapter
.Use(new AutoSaveStateMiddleware(convoState));
// Create new DialogSet
var dialogs = new DialogSet(dialogState);
dialogs.Add(new OAuthPrompt("OAuthPrompt", oAuthPromptSettings));
BotCallbackHandler botCallbackHandler = async (turnContext, cancellationToken) =>
{
var dc = await dialogs.CreateContextAsync(turnContext, cancellationToken);
var results = await dc.ContinueDialogAsync(cancellationToken);
if (results.Status == DialogTurnStatus.Empty)
{
await dc.PromptAsync("OAuthPrompt", new PromptOptions(), cancellationToken: cancellationToken);
}
};
await new TestFlow(adapter, botCallbackHandler)
.Send("hello")
.AssertReply(activity =>
{
Assert.Single(((Activity)activity).Attachments);
Assert.Equal(OAuthCard.ContentType, ((Activity)activity).Attachments[0].ContentType);
var oAuthCard = (OAuthCard)((Activity)activity).Attachments[0].Content;
if (containsSasurl)
{
Assert.NotNull(oAuthCard.TokenPostResource);
Assert.NotNull(oAuthCard.TokenPostResource.SasUrl);
}
else
{
Assert.Null(oAuthCard.TokenPostResource);
}
Assert.NotNull(oAuthCard.TokenExchangeResource);
})
.StartTestAsync();
}
[Fact]
public async Task OAuthPromptEndOnInvalidMessageSetting()
{
@ -788,7 +846,7 @@ namespace Microsoft.Bot.Builder.Dialogs.Tests
var turnContext = new TurnContext(adapter, activity);
var userToken = await prompt.GetUserTokenAsync(turnContext, CancellationToken.None);
Assert.Equal(Token, userToken.Token);
}
@ -919,5 +977,18 @@ namespace Microsoft.Bot.Builder.Dialogs.Tests
return eventActivity;
}
private class SignInResourceAdapter : TestAdapter
{
public override async Task<SignInResource> GetSignInResourceAsync(ITurnContext turnContext, AppCredentials oAuthAppCredentials, string connectionName, string userId, string finalRedirect = null, CancellationToken cancellationToken = default)
{
var result = await base.GetSignInResourceAsync(turnContext, oAuthAppCredentials, connectionName, userId, finalRedirect, cancellationToken);
result.TokenPostResource = new TokenPostResource()
{
SasUrl = $"https://www.fakesas.com/{connectionName}/{userId}"
};
return result;
}
}
}
}