From 822ae31831ed4b9ec19dbcdee17dcbd9aa0f5b02 Mon Sep 17 00:00:00 2001 From: fangyangci <133664123+fangyangci@users.noreply.github.com> Date: Tue, 19 Dec 2023 22:43:50 +0800 Subject: [PATCH] fix: USGovSingleTenant OAuthEndpoint (#6714) * fixUSGovSingleTenant * Add UT * Rollback AuthTenant Property Name * The Ctor do contains the old ones, Add Ctor to ApiCompatBaseline --- ApiCompatBaseline.txt | 11 +++- .../Authentication/AppCredentials.cs | 38 ++++++++++-- .../GovernmentAuthenticationConstants.cs | 16 ++++- ...vernmentCloudBotFrameworkAuthentication.cs | 2 +- .../Authentication/MicrosoftAppCredentials.cs | 62 +------------------ .../MicrosoftGovernmentAppCredentials.cs | 52 +++++----------- .../MsalServiceClientCredentialsFactory.cs | 16 +++-- .../PasswordServiceClientCredentialFactory.cs | 4 +- .../MicrosoftAppCredentialsTests.cs | 58 ++++++++++------- .../MicrosoftGovernmentAppCredentialsTests.cs | 57 ++++++++++++++--- 10 files changed, 174 insertions(+), 142 deletions(-) diff --git a/ApiCompatBaseline.txt b/ApiCompatBaseline.txt index dd119bc045..1beec09e2b 100644 --- a/ApiCompatBaseline.txt +++ b/ApiCompatBaseline.txt @@ -3,9 +3,18 @@ TypesMustExist : Type 'Microsoft.Bot.Builder.Azure.CosmosDbCustomClientOptions' TypesMustExist : Type 'Microsoft.Bot.Builder.Azure.CosmosDbStorage' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Microsoft.Bot.Builder.Azure.CosmosDbStorageOptions' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials..ctor(System.String, System.String)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials..ctor(System.String, System.String, System.Net.Http.HttpClient)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials..ctor(System.String, System.String, System.Net.Http.HttpClient, Microsoft.Extensions.Logging.ILogger)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials..ctor(System.String, System.String, System.String, System.Net.Http.HttpClient)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials..ctor(System.String, System.String, System.String, System.Net.Http.HttpClient, Microsoft.Extensions.Logging.ILogger)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftGovernmentAppCredentials..ctor(System.String, System.String, System.Net.Http.HttpClient)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftGovernmentAppCredentials..ctor(System.String, System.String, System.Net.Http.HttpClient, Microsoft.Extensions.Logging.ILogger)' does not exist in the implementation but it does exist in the contract. + TypesMustExist : Type 'Microsoft.Bot.Connector.Authentication.AdalAuthenticator' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.AppCredentials.BuildAuthenticator()' does not exist in the implementation but it does exist in the contract. CannotAddAbstractMembers : Member 'Microsoft.Bot.Connector.Authentication.AppCredentials.BuildIAuthenticator()' is abstract in the implementation but is missing in the contract. MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.CertificateAppCredentials..ctor(Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate, System.String, System.Net.Http.HttpClient, Microsoft.Extensions.Logging.ILogger)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.CertificateAppCredentials.BuildAuthenticator()' does not exist in the implementation but it does exist in the contract. -MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials.BuildAuthenticator()' does not exist in the implementation but it does exist in the contract. \ No newline at end of file +MembersMustExist : Member 'Microsoft.Bot.Connector.Authentication.MicrosoftAppCredentials.BuildAuthenticator()' does not exist in the implementation but it does exist in the contract. + diff --git a/libraries/Microsoft.Bot.Connector/Authentication/AppCredentials.cs b/libraries/Microsoft.Bot.Connector/Authentication/AppCredentials.cs index bc2e335099..73eebe442b 100644 --- a/libraries/Microsoft.Bot.Connector/Authentication/AppCredentials.cs +++ b/libraries/Microsoft.Bot.Connector/Authentication/AppCredentials.cs @@ -34,6 +34,8 @@ public abstract class AppCredentials : ServiceClientCredentials /// private Lazy _authenticator; + private string _oAuthScope; + /// /// Initializes a new instance of the class. /// @@ -54,7 +56,7 @@ public AppCredentials(string channelAuthTenant = null, HttpClient customHttpClie /// The scope for the token. public AppCredentials(string channelAuthTenant = null, HttpClient customHttpClient = null, ILogger logger = null, string oAuthScope = null) { - OAuthScope = string.IsNullOrWhiteSpace(oAuthScope) ? AuthenticationConstants.ToChannelFromBotOAuthScope : oAuthScope; + _oAuthScope = oAuthScope; ChannelAuthTenant = channelAuthTenant; CustomHttpClient = customHttpClient; Logger = logger ?? NullLogger.Instance; @@ -74,13 +76,15 @@ public AppCredentials(string channelAuthTenant = null, HttpClient customHttpClie /// /// Tenant to be used for channel authentication. /// - public string ChannelAuthTenant + public virtual string ChannelAuthTenant { - get => string.IsNullOrEmpty(AuthTenant) ? AuthenticationConstants.DefaultChannelAuthTenant : AuthTenant; + get => string.IsNullOrEmpty(AuthTenant) + ? DefaultChannelAuthTenant + : AuthTenant; set { // Advanced user only, see https://aka.ms/bots/tenant-restriction - var endpointUrl = string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ToChannelFromBotLoginUrlTemplate, value); + var endpointUrl = string.Format(CultureInfo.InvariantCulture, ToChannelFromBotLoginUrlTemplate, value); if (Uri.TryCreate(endpointUrl, UriKind.Absolute, out _)) { @@ -99,7 +103,7 @@ public string ChannelAuthTenant /// /// The OAuth endpoint to use. /// - public virtual string OAuthEndpoint => string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ToChannelFromBotLoginUrlTemplate, ChannelAuthTenant); + public virtual string OAuthEndpoint => string.Format(CultureInfo.InvariantCulture, ToChannelFromBotLoginUrlTemplate, ChannelAuthTenant); /// /// Gets a value indicating whether to validate the Authority. @@ -115,7 +119,9 @@ public string ChannelAuthTenant /// /// The OAuth scope to use. /// - public virtual string OAuthScope { get; } + public virtual string OAuthScope => string.IsNullOrEmpty(_oAuthScope) + ? ToChannelFromBotOAuthScope + : _oAuthScope; /// /// Gets or sets the channel auth token tenant for this credential. @@ -141,6 +147,26 @@ public string ChannelAuthTenant /// protected ILogger Logger { get; set; } + /// + /// Gets DefaultChannelAuthTenant. + /// + /// DefaultChannelAuthTenant. + protected virtual string DefaultChannelAuthTenant => AuthenticationConstants.DefaultChannelAuthTenant; + + /// + /// Gets ToChannelFromBotOAuthScope. + /// + /// ToChannelFromBotOAuthScope. + protected virtual string ToChannelFromBotOAuthScope => AuthenticationConstants.ToChannelFromBotOAuthScope; + + /// + /// Gets ToChannelFromBotLoginUrlTemplate. + /// + /// ToChannelFromBotLoginUrlTemplate. +#pragma warning disable CA1056 // Uri properties should not be strings + protected virtual string ToChannelFromBotLoginUrlTemplate => AuthenticationConstants.ToChannelFromBotLoginUrlTemplate; +#pragma warning restore CA1056 // Uri properties should not be strings + /// /// Adds the host of service url to trusted hosts. /// diff --git a/libraries/Microsoft.Bot.Connector/Authentication/GovernmentAuthenticationConstants.cs b/libraries/Microsoft.Bot.Connector/Authentication/GovernmentAuthenticationConstants.cs index e961808ffd..6bfb1989d8 100644 --- a/libraries/Microsoft.Bot.Connector/Authentication/GovernmentAuthenticationConstants.cs +++ b/libraries/Microsoft.Bot.Connector/Authentication/GovernmentAuthenticationConstants.cs @@ -14,10 +14,24 @@ public static class GovernmentAuthenticationConstants public const string ChannelService = "https://botframework.azure.us"; /// - /// TO GOVERNMENT CHANNEL FROM BOT: Login URL. + /// TO CHANNEL FROM BOT: Login URL. + /// + /// DEPRECATED. For binary compat only. /// public const string ToChannelFromBotLoginUrl = "https://login.microsoftonline.us/MicrosoftServices.onmicrosoft.us"; + /// + /// TO CHANNEL FROM BOT: Login URL template string. Bot developer may specify + /// which tenant to obtain an access token from. By default, the channels only + /// accept tokens from "MicrosoftServices.onmicrosoft.us". For more details see https://aka.ms/bots/tenant-restriction. + /// + public const string ToChannelFromBotLoginUrlTemplate = "https://login.microsoftonline.us/{0}"; + + /// + /// The default tenant to acquire bot to channel token from. + /// + public const string DefaultChannelAuthTenant = "MicrosoftServices.onmicrosoft.us"; + /// /// TO GOVERNMENT CHANNEL FROM BOT: OAuth scope to request. /// diff --git a/libraries/Microsoft.Bot.Connector/Authentication/GovernmentCloudBotFrameworkAuthentication.cs b/libraries/Microsoft.Bot.Connector/Authentication/GovernmentCloudBotFrameworkAuthentication.cs index 545720488d..6403417df1 100644 --- a/libraries/Microsoft.Bot.Connector/Authentication/GovernmentCloudBotFrameworkAuthentication.cs +++ b/libraries/Microsoft.Bot.Connector/Authentication/GovernmentCloudBotFrameworkAuthentication.cs @@ -12,7 +12,7 @@ internal class GovernmentCloudBotFrameworkAuthentication : BuiltinBotFrameworkAu public GovernmentCloudBotFrameworkAuthentication(ServiceClientCredentialsFactory credentialFactory, AuthenticationConfiguration authConfiguration, IHttpClientFactory httpClientFactory, ILogger logger = null) : base( GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope, - GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl, + GovernmentAuthenticationConstants.ToChannelFromBotLoginUrlTemplate, CallerIdConstants.USGovChannel, GovernmentAuthenticationConstants.ChannelService, GovernmentAuthenticationConstants.OAuthUrlGov, diff --git a/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftAppCredentials.cs b/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftAppCredentials.cs index add80a0471..dc1cec4942 100644 --- a/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftAppCredentials.cs +++ b/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftAppCredentials.cs @@ -38,39 +38,6 @@ public class MicrosoftAppCredentials : AppCredentials /// public static readonly MicrosoftAppCredentials Empty = new MicrosoftAppCredentials(null, null); - /// - /// Initializes a new instance of the class. - /// - /// The Microsoft app ID. - /// The Microsoft app password. - public MicrosoftAppCredentials(string appId, string password) - : this(appId, password, null, null, null, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The Microsoft app ID. - /// The Microsoft app password. - /// Optional to be used when acquiring tokens. - public MicrosoftAppCredentials(string appId, string password, HttpClient customHttpClient) - : this(appId, password, null, customHttpClient) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The Microsoft app ID. - /// The Microsoft app password. - /// Optional to be used when acquiring tokens. - /// Optional to gather telemetry data while acquiring and managing credentials. - public MicrosoftAppCredentials(string appId, string password, HttpClient customHttpClient, ILogger logger) - : this(appId, password, null, customHttpClient, logger) - { - } - /// /// Initializes a new instance of the class. /// @@ -79,36 +46,11 @@ public MicrosoftAppCredentials(string appId, string password, HttpClient customH /// Optional to be used when acquiring tokens. /// Optional to gather telemetry data while acquiring and managing credentials. /// The scope for the token. - public MicrosoftAppCredentials(string appId, string password, HttpClient customHttpClient, ILogger logger, string oAuthScope) + public MicrosoftAppCredentials(string appId, string password, HttpClient customHttpClient = null, ILogger logger = null, string oAuthScope = null) : this(appId, password, null, customHttpClient, logger, oAuthScope) { } - /// - /// Initializes a new instance of the class. - /// - /// The Microsoft app ID. - /// The Microsoft app password. - /// Optional. The oauth token tenant. - /// Optional to be used when acquiring tokens. - public MicrosoftAppCredentials(string appId, string password, string channelAuthTenant, HttpClient customHttpClient) - : this(appId, password, channelAuthTenant, customHttpClient, null) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The Microsoft app ID. - /// The Microsoft app password. - /// Optional. The oauth token tenant. - /// Optional to be used when acquiring tokens. - /// Optional to gather telemetry data while acquiring and managing credentials. - public MicrosoftAppCredentials(string appId, string password, string channelAuthTenant, HttpClient customHttpClient, ILogger logger = null) - : this(appId, password, channelAuthTenant, customHttpClient, logger, null) - { - } - /// /// Initializes a new instance of the class. /// @@ -118,7 +60,7 @@ public MicrosoftAppCredentials(string appId, string password, string channelAuth /// Optional to be used when acquiring tokens. /// Optional to gather telemetry data while acquiring and managing credentials. /// The scope for the token. - public MicrosoftAppCredentials(string appId, string password, string channelAuthTenant, HttpClient customHttpClient, ILogger logger = null, string oAuthScope = null) + public MicrosoftAppCredentials(string appId, string password, string channelAuthTenant, HttpClient customHttpClient = null, ILogger logger = null, string oAuthScope = null) : base(channelAuthTenant, customHttpClient, logger, oAuthScope) { MicrosoftAppId = appId; diff --git a/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftGovernmentAppCredentials.cs b/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftGovernmentAppCredentials.cs index 7839abbc11..50df6fa1a7 100644 --- a/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftGovernmentAppCredentials.cs +++ b/libraries/Microsoft.Bot.Connector/Authentication/MicrosoftGovernmentAppCredentials.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Globalization; using System.Net.Http; using Microsoft.Extensions.Logging; @@ -16,29 +17,6 @@ public class MicrosoftGovernmentAppCredentials : MicrosoftAppCredentials /// public static new readonly MicrosoftGovernmentAppCredentials Empty = new MicrosoftGovernmentAppCredentials(null, null, null, null, GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope); - /// - /// Initializes a new instance of the class. - /// - /// The Microsoft app ID. - /// The Microsoft app password. - /// Optional to be used when acquiring tokens. - public MicrosoftGovernmentAppCredentials(string appId, string password, HttpClient customHttpClient = null) - : this(appId, password, customHttpClient, null, GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The Microsoft app ID. - /// The Microsoft app password. - /// Optional to be used when acquiring tokens. - /// Optional to gather telemetry data while acquiring and managing credentials. - public MicrosoftGovernmentAppCredentials(string appId, string password, HttpClient customHttpClient, ILogger logger) - : this(appId, password, customHttpClient, logger, GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope) - { - } - /// /// Initializes a new instance of the class. /// @@ -47,8 +25,8 @@ public MicrosoftGovernmentAppCredentials(string appId, string password, HttpClie /// Optional to be used when acquiring tokens. /// Optional to gather telemetry data while acquiring and managing credentials. /// The scope for the token (defaults to if null). - public MicrosoftGovernmentAppCredentials(string appId, string password, HttpClient customHttpClient, ILogger logger, string oAuthScope = null) - : this(appId, password, tenantId: string.Empty, customHttpClient, logger, oAuthScope) + public MicrosoftGovernmentAppCredentials(string appId, string password, HttpClient customHttpClient = null, ILogger logger = null, string oAuthScope = null) + : base(appId, password, customHttpClient, logger, oAuthScope) { } @@ -57,24 +35,22 @@ public MicrosoftGovernmentAppCredentials(string appId, string password, HttpClie /// /// The Microsoft app ID. /// The Microsoft app password. - /// Tenant ID of the Azure AD tenant where the bot is created. + /// Optional. The oauth token tenant. /// Optional to be used when acquiring tokens. /// Optional to gather telemetry data while acquiring and managing credentials. /// The scope for the token (defaults to if null). - public MicrosoftGovernmentAppCredentials(string appId, string password, string tenantId, HttpClient customHttpClient, ILogger logger, string oAuthScope = null) - : base(appId, password, tenantId, customHttpClient, logger, oAuthScope ?? GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope) + public MicrosoftGovernmentAppCredentials(string appId, string password, string channelAuthTenant, HttpClient customHttpClient = null, ILogger logger = null, string oAuthScope = null) + : base(appId, password, channelAuthTenant, customHttpClient, logger, oAuthScope) { } - /// - /// Gets the OAuth endpoint to use. - /// - /// - /// The OAuth endpoint to use. - /// - public override string OAuthEndpoint - { - get { return GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl; } - } + /// + protected override string DefaultChannelAuthTenant => GovernmentAuthenticationConstants.DefaultChannelAuthTenant; + + /// + protected override string ToChannelFromBotOAuthScope => GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope; + + /// + protected override string ToChannelFromBotLoginUrlTemplate => GovernmentAuthenticationConstants.ToChannelFromBotLoginUrlTemplate; } } diff --git a/libraries/Microsoft.Bot.Connector/Authentication/MsalServiceClientCredentialsFactory.cs b/libraries/Microsoft.Bot.Connector/Authentication/MsalServiceClientCredentialsFactory.cs index 986917c0ea..7b39e34008 100644 --- a/libraries/Microsoft.Bot.Connector/Authentication/MsalServiceClientCredentialsFactory.cs +++ b/libraries/Microsoft.Bot.Connector/Authentication/MsalServiceClientCredentialsFactory.cs @@ -59,22 +59,28 @@ public override Task CreateCredentialsAsync(string app } // Public cloud: default authority, optional scope when authenticating for skill communication. - if (loginEndpoint.StartsWith(AuthenticationConstants.ToChannelFromBotLoginUrlTemplate, StringComparison.OrdinalIgnoreCase)) + if (loginEndpoint.Equals(AuthenticationConstants.ToChannelFromBotLoginUrlTemplate, StringComparison.OrdinalIgnoreCase)) { return Task.FromResult( - new MsalAppCredentials(_clientApplication, appId, authority: null, scope: audience, validateAuthority: validateAuthority, logger: _logger)); + new MsalAppCredentials( + _clientApplication, + appId, + authority: null, + scope: audience, + validateAuthority: validateAuthority, + logger: _logger)); } // Legacy gov: Set the authority (login url) to the legacy gov url, and allow for passed in scope for skill auth in // gov, or otherwise leave the default channel scope for gov. - if (loginEndpoint.Equals(GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl, StringComparison.OrdinalIgnoreCase)) + if (loginEndpoint.Equals(GovernmentAuthenticationConstants.ToChannelFromBotLoginUrlTemplate, StringComparison.OrdinalIgnoreCase)) { return Task.FromResult( new MsalAppCredentials( _clientApplication, appId, - authority: GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl, - scope: audience ?? GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope, + authority: null, + scope: audience, validateAuthority: validateAuthority, logger: _logger)); } diff --git a/libraries/Microsoft.Bot.Connector/Authentication/PasswordServiceClientCredentialFactory.cs b/libraries/Microsoft.Bot.Connector/Authentication/PasswordServiceClientCredentialFactory.cs index ca4050ea90..5319b78f95 100644 --- a/libraries/Microsoft.Bot.Connector/Authentication/PasswordServiceClientCredentialFactory.cs +++ b/libraries/Microsoft.Bot.Connector/Authentication/PasswordServiceClientCredentialFactory.cs @@ -93,12 +93,12 @@ public override Task CreateCredentialsAsync(string app throw new InvalidOperationException($"Invalid appId {appId} does not match expected {AppId}"); } - if (loginEndpoint.StartsWith(AuthenticationConstants.ToChannelFromBotLoginUrlTemplate, StringComparison.OrdinalIgnoreCase)) + if (loginEndpoint.Equals(AuthenticationConstants.ToChannelFromBotLoginUrlTemplate, StringComparison.OrdinalIgnoreCase)) { return Task.FromResult(new MicrosoftAppCredentials( appId, Password, TenantId, _httpClient, _logger, oauthScope)); } - else if (loginEndpoint.Equals(GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl, StringComparison.OrdinalIgnoreCase)) + else if (loginEndpoint.Equals(GovernmentAuthenticationConstants.ToChannelFromBotLoginUrlTemplate, StringComparison.OrdinalIgnoreCase)) { return Task.FromResult(new MicrosoftGovernmentAppCredentials( appId, Password, TenantId, _httpClient, _logger, oauthScope)); diff --git a/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftAppCredentialsTests.cs b/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftAppCredentialsTests.cs index 9298ee05d3..1b71835568 100644 --- a/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftAppCredentialsTests.cs +++ b/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftAppCredentialsTests.cs @@ -1,10 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System.Net.Http; +using System.Globalization; using Microsoft.Bot.Connector.Authentication; -using Microsoft.Extensions.Logging; -using Moq; using Xunit; namespace Microsoft.Bot.Connector.Tests.Authentication @@ -15,30 +13,48 @@ public class MicrosoftAppCredentialsTests public void ConstructorTests() { var defaultScopeCase1 = new MicrosoftAppCredentials("someApp", "somePassword"); - Assert.Equal(AuthenticationConstants.ToChannelFromBotOAuthScope, defaultScopeCase1.OAuthScope); + AssertEqual(defaultScopeCase1, null, null); - using (var customHttpClient = new HttpClient()) - { - // Use with default scope - var defaultScopeCase2 = new MicrosoftAppCredentials("someApp", "somePassword", customHttpClient); - Assert.Equal(AuthenticationConstants.ToChannelFromBotOAuthScope, defaultScopeCase2.OAuthScope); + var defaultScopeCase2 = new MicrosoftAppCredentials("someApp", "somePassword", oAuthScope: "customScope"); + AssertEqual(defaultScopeCase2, null, "customScope"); - var logger = new Mock().Object; - var defaultScopeCase3 = new MicrosoftAppCredentials("someApp", "somePassword", customHttpClient, logger); - Assert.Equal(AuthenticationConstants.ToChannelFromBotOAuthScope, defaultScopeCase3.OAuthScope); + var defaultScopeCase3 = new MicrosoftAppCredentials("someApp", "somePassword", "someTenant"); + AssertEqual(defaultScopeCase3, "someTenant", null); - var defaultScopeCase4 = new MicrosoftAppCredentials("someApp", "somePassword", "someTenant", customHttpClient); - Assert.Equal(AuthenticationConstants.ToChannelFromBotOAuthScope, defaultScopeCase4.OAuthScope); + var defaultScopeCase4 = new MicrosoftAppCredentials("someApp", "somePassword", "someTenant", oAuthScope: "customScope"); + AssertEqual(defaultScopeCase4, "someTenant", "customScope"); + } - var defaultScopeCase5 = new MicrosoftAppCredentials("someApp", "somePassword", "someTenant", customHttpClient, logger); - Assert.Equal(AuthenticationConstants.ToChannelFromBotOAuthScope, defaultScopeCase5.OAuthScope); + private void AssertEqual(MicrosoftAppCredentials credential, string tenantId, string oauthScope) + { + Assert.Equal( + string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ToChannelFromBotLoginUrlTemplate, credential.ChannelAuthTenant), + credential.OAuthEndpoint); - // Use custom scope - var customScopeCase1 = new MicrosoftAppCredentials("someApp", "somePassword", customHttpClient, logger, "customScope"); - Assert.Equal("customScope", customScopeCase1.OAuthScope); + if (string.IsNullOrEmpty(oauthScope)) + { + Assert.Equal( + AuthenticationConstants.ToChannelFromBotOAuthScope, + credential.OAuthScope); + } + else + { + Assert.Equal( + oauthScope, + credential.OAuthScope); + } - var customScopeCase2 = new MicrosoftAppCredentials("someApp", "somePassword", "someTenant", customHttpClient, logger, "customScope"); - Assert.Equal("customScope", customScopeCase2.OAuthScope); + if (string.IsNullOrEmpty(tenantId)) + { + Assert.Equal( + AuthenticationConstants.DefaultChannelAuthTenant, + credential.ChannelAuthTenant); + } + else + { + Assert.Equal( + tenantId, + credential.ChannelAuthTenant); } } } diff --git a/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftGovernmentAppCredentialsTests.cs b/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftGovernmentAppCredentialsTests.cs index 5ffda0042b..323eaac4eb 100644 --- a/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftGovernmentAppCredentialsTests.cs +++ b/tests/Microsoft.Bot.Connector.Tests/Authentication/MicrosoftGovernmentAppCredentialsTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System.Globalization; using Microsoft.Bot.Connector.Authentication; using Xunit; @@ -39,13 +40,6 @@ public void GovernmentAuthenticationConstants_ChannelService_IsRight() Assert.Equal("https://botframework.azure.us", GovernmentAuthenticationConstants.ChannelService); } - [Fact] - public void GovernmentAuthenticationConstants_ToChannelFromBotLoginUrl_IsRight() - { - // This value should not change - Assert.Equal("https://login.microsoftonline.us/MicrosoftServices.onmicrosoft.us", GovernmentAuthenticationConstants.ToChannelFromBotLoginUrl); - } - [Fact] public void GovernmentAuthenticationConstants_ToChannelFromBotOAuthScope_IsRight() { @@ -73,5 +67,54 @@ public void GovernmentAuthenticationConstants_ToBotFromChannelOpenIdMetadataUrl_ // This value should not change Assert.Equal("https://login.botframework.azure.us/v1/.well-known/openidconfiguration", GovernmentAuthenticationConstants.ToBotFromChannelOpenIdMetadataUrl); } + + [Fact] + public void ConstructorTests() + { + var defaultScopeCase1 = new MicrosoftGovernmentAppCredentials("someApp", "somePassword"); + AssertEqual(defaultScopeCase1, null, null); + + var defaultScopeCase2 = new MicrosoftGovernmentAppCredentials("someApp", "somePassword", oAuthScope: "customScope"); + AssertEqual(defaultScopeCase2, null, "customScope"); + + var defaultScopeCase3 = new MicrosoftGovernmentAppCredentials("someApp", "somePassword", "someTenant"); + AssertEqual(defaultScopeCase3, "someTenant", null); + + var defaultScopeCase4 = new MicrosoftGovernmentAppCredentials("someApp", "somePassword", "someTenant", oAuthScope: "customScope"); + AssertEqual(defaultScopeCase4, "someTenant", "customScope"); + } + + private void AssertEqual(MicrosoftGovernmentAppCredentials credential, string tenantId, string oauthScope) + { + Assert.Equal( + string.Format(CultureInfo.InvariantCulture, GovernmentAuthenticationConstants.ToChannelFromBotLoginUrlTemplate, credential.ChannelAuthTenant), + credential.OAuthEndpoint); + + if (string.IsNullOrEmpty(oauthScope)) + { + Assert.Equal( + GovernmentAuthenticationConstants.ToChannelFromBotOAuthScope, + credential.OAuthScope); + } + else + { + Assert.Equal( + oauthScope, + credential.OAuthScope); + } + + if (string.IsNullOrEmpty(tenantId)) + { + Assert.Equal( + GovernmentAuthenticationConstants.DefaultChannelAuthTenant, + credential.ChannelAuthTenant); + } + else + { + Assert.Equal( + tenantId, + credential.ChannelAuthTenant); + } + } } }