diff --git a/sdk/identity/Azure.Identity/CHANGELOG.md b/sdk/identity/Azure.Identity/CHANGELOG.md index 6b394fdbd055..30d139be8061 100644 --- a/sdk/identity/Azure.Identity/CHANGELOG.md +++ b/sdk/identity/Azure.Identity/CHANGELOG.md @@ -16,6 +16,11 @@ ## 1.5.0-beta.1 (2021-06-08) +### New Features +- Added regional STS support to client credential types + - Added `RegionalAuthority` extensible enum + - Added `RegionalAuthority` property to `ClientSecretCredentialOptions` and `ClientCertificateCredentialOptions` + ### Fixes and improvements - Added `LoginHint` property to `InteractiveBrowserCredentialOptions` which allows a user name to be pre-selected for interactive logins. Setting this option skips the account selection prompt and immediately attempts to login with the specified account. diff --git a/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs b/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs index 47246c16b76b..5beb367bfbbe 100644 --- a/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs +++ b/sdk/identity/Azure.Identity/api/Azure.Identity.netstandard2.0.cs @@ -92,6 +92,7 @@ public ClientCertificateCredential(string tenantId, string clientId, string clie public partial class ClientCertificateCredentialOptions : Azure.Identity.TokenCredentialOptions { public ClientCertificateCredentialOptions() { } + public Azure.Identity.RegionalAuthority? RegionalAuthority { get { throw null; } set { } } public bool SendCertificateChain { get { throw null; } set { } } public Azure.Identity.TokenCachePersistenceOptions TokenCachePersistenceOptions { get { throw null; } set { } } } @@ -107,6 +108,7 @@ public ClientSecretCredential(string tenantId, string clientId, string clientSec public partial class ClientSecretCredentialOptions : Azure.Identity.TokenCredentialOptions { public ClientSecretCredentialOptions() { } + public Azure.Identity.RegionalAuthority? RegionalAuthority { get { throw null; } set { } } public Azure.Identity.TokenCachePersistenceOptions TokenCachePersistenceOptions { get { throw null; } set { } } } public partial class CredentialUnavailableException : Azure.Identity.AuthenticationFailedException @@ -223,6 +225,75 @@ public ManagedIdentityCredential(string clientId = null, Azure.Identity.TokenCre public override Azure.Core.AccessToken GetToken(Azure.Core.TokenRequestContext requestContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override System.Threading.Tasks.ValueTask GetTokenAsync(Azure.Core.TokenRequestContext requestContext, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } } + [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] + public readonly partial struct RegionalAuthority : System.IEquatable + { + private readonly object _dummy; + private readonly int _dummyPrimitive; + public RegionalAuthority(string value) { throw null; } + public static Azure.Identity.RegionalAuthority AsiaEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority AsiaSouthEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority AustraliaCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority AustraliaCentral2 { get { throw null; } } + public static Azure.Identity.RegionalAuthority AustraliaEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority AustraliaSouthEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority AutoDiscoverRegion { get { throw null; } } + public static Azure.Identity.RegionalAuthority BrazilSouth { get { throw null; } } + public static Azure.Identity.RegionalAuthority CanadaCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority CanadaEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority ChinaEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority ChinaEast2 { get { throw null; } } + public static Azure.Identity.RegionalAuthority ChinaNorth { get { throw null; } } + public static Azure.Identity.RegionalAuthority ChinaNorth2 { get { throw null; } } + public static Azure.Identity.RegionalAuthority EuropeNorth { get { throw null; } } + public static Azure.Identity.RegionalAuthority EuropeWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority FranceCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority FranceSouth { get { throw null; } } + public static Azure.Identity.RegionalAuthority GermanyCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority GermanyNorth { get { throw null; } } + public static Azure.Identity.RegionalAuthority GermanyNorthEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority GermanyWestCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority GovernmentUSArizona { get { throw null; } } + public static Azure.Identity.RegionalAuthority GovernmentUSDodCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority GovernmentUSDodEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority GovernmentUSIowa { get { throw null; } } + public static Azure.Identity.RegionalAuthority GovernmentUSTexas { get { throw null; } } + public static Azure.Identity.RegionalAuthority GovernmentUSVirginia { get { throw null; } } + public static Azure.Identity.RegionalAuthority IndiaCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority IndiaSouth { get { throw null; } } + public static Azure.Identity.RegionalAuthority IndiaWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority JapanEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority JapanWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority KoreaCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority KoreaSouth { get { throw null; } } + public static Azure.Identity.RegionalAuthority NorwayEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority NorwayWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority SouthAfricaNorth { get { throw null; } } + public static Azure.Identity.RegionalAuthority SouthAfricaWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority SwitzerlandNorth { get { throw null; } } + public static Azure.Identity.RegionalAuthority SwitzerlandWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority UAECentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority UAENorth { get { throw null; } } + public static Azure.Identity.RegionalAuthority UKSouth { get { throw null; } } + public static Azure.Identity.RegionalAuthority UKWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority USCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority USEast { get { throw null; } } + public static Azure.Identity.RegionalAuthority USEast2 { get { throw null; } } + public static Azure.Identity.RegionalAuthority USNorthCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority USSouthCentral { get { throw null; } } + public static Azure.Identity.RegionalAuthority USWest { get { throw null; } } + public static Azure.Identity.RegionalAuthority USWest2 { get { throw null; } } + public static Azure.Identity.RegionalAuthority USWestCentral { get { throw null; } } + public bool Equals(Azure.Identity.RegionalAuthority other) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override bool Equals(object obj) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override int GetHashCode() { throw null; } + public static bool operator ==(Azure.Identity.RegionalAuthority left, Azure.Identity.RegionalAuthority right) { throw null; } + public static implicit operator Azure.Identity.RegionalAuthority (string value) { throw null; } + public static bool operator !=(Azure.Identity.RegionalAuthority left, Azure.Identity.RegionalAuthority right) { throw null; } + public override string ToString() { throw null; } + } public partial class SharedTokenCacheCredential : Azure.Core.TokenCredential { public SharedTokenCacheCredential() { } diff --git a/sdk/identity/Azure.Identity/src/AuthorizationCodeCredential.cs b/sdk/identity/Azure.Identity/src/AuthorizationCodeCredential.cs index 48c80916d114..d5a49ab297ec 100644 --- a/sdk/identity/Azure.Identity/src/AuthorizationCodeCredential.cs +++ b/sdk/identity/Azure.Identity/src/AuthorizationCodeCredential.cs @@ -93,7 +93,7 @@ internal AuthorizationCodeCredential(string tenantId, string clientId, string cl _ => null }; - _client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, clientSecret, options as ITokenCacheOptions); + _client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, clientSecret, options as ITokenCacheOptions, null); } /// diff --git a/sdk/identity/Azure.Identity/src/ClientCertificateCredential.cs b/sdk/identity/Azure.Identity/src/ClientCertificateCredential.cs index da450d1b2c53..b03914ebcb49 100644 --- a/sdk/identity/Azure.Identity/src/ClientCertificateCredential.cs +++ b/sdk/identity/Azure.Identity/src/ClientCertificateCredential.cs @@ -32,7 +32,8 @@ public class ClientCertificateCredential : TokenCredential internal IX509Certificate2Provider ClientCertificateProvider { get; } - private readonly MsalConfidentialClient _client; + internal MsalConfidentialClient Client { get; } + private readonly CredentialPipeline _pipeline; private readonly bool _allowMultiTenantAuthentication; @@ -131,7 +132,9 @@ internal ClientCertificateCredential(string tenantId, string clientId, IX509Cert _pipeline = pipeline ?? CredentialPipeline.GetInstance(options); - _client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, certificateProvider, (options as ClientCertificateCredentialOptions)?.SendCertificateChain ?? false, options as ITokenCacheOptions); + ClientCertificateCredentialOptions certCredOptions = (options as ClientCertificateCredentialOptions); + + Client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, certificateProvider, certCredOptions?.SendCertificateChain ?? false, options as ITokenCacheOptions, certCredOptions?.RegionalAuthority); } /// @@ -147,7 +150,7 @@ public override AccessToken GetToken(TokenRequestContext requestContext, Cancell try { var tenantId = TenantIdResolver.Resolve(TenantId, requestContext, _allowMultiTenantAuthentication); - AuthenticationResult result = _client.AcquireTokenForClientAsync(requestContext.Scopes, tenantId, false, cancellationToken).EnsureCompleted(); + AuthenticationResult result = Client.AcquireTokenForClientAsync(requestContext.Scopes, tenantId, false, cancellationToken).EnsureCompleted(); return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn)); } @@ -170,7 +173,7 @@ public override async ValueTask GetTokenAsync(TokenRequestContext r try { var tenantId = TenantIdResolver.Resolve(TenantId, requestContext, _allowMultiTenantAuthentication); - AuthenticationResult result = await _client + AuthenticationResult result = await Client .AcquireTokenForClientAsync(requestContext.Scopes, tenantId, true, cancellationToken) .ConfigureAwait(false); diff --git a/sdk/identity/Azure.Identity/src/ClientCertificateCredentialOptions.cs b/sdk/identity/Azure.Identity/src/ClientCertificateCredentialOptions.cs index 4943d9fe47da..558c2943b4b3 100644 --- a/sdk/identity/Azure.Identity/src/ClientCertificateCredentialOptions.cs +++ b/sdk/identity/Azure.Identity/src/ClientCertificateCredentialOptions.cs @@ -17,5 +17,11 @@ public class ClientCertificateCredentialOptions : TokenCredentialOptions, IToken /// Will include x5c header in client claims when acquiring a token to enable subject name / issuer based authentication for the . /// public bool SendCertificateChain { get; set; } + + /// + /// Specifies either the specific (preferred), or use to attempt to auto-detect the region. + /// If not specified or auto-detection fails the non-regional endpoint will be used. + /// + public RegionalAuthority? RegionalAuthority { get; set; } = Azure.Identity.RegionalAuthority.FromEnvironment(); } } diff --git a/sdk/identity/Azure.Identity/src/ClientSecretCredential.cs b/sdk/identity/Azure.Identity/src/ClientSecretCredential.cs index 80f3bfd2a7a7..ba8fc9144011 100644 --- a/sdk/identity/Azure.Identity/src/ClientSecretCredential.cs +++ b/sdk/identity/Azure.Identity/src/ClientSecretCredential.cs @@ -18,9 +18,10 @@ namespace Azure.Identity /// public class ClientSecretCredential : TokenCredential { - private readonly MsalConfidentialClient _client; private readonly CredentialPipeline _pipeline; - private readonly bool _allowMultiTenantAuthentication; + private readonly bool _allowMultiTenantAuthentication; + + internal MsalConfidentialClient Client { get; } /// /// Gets the Azure Active Directory tenant (directory) Id of the service principal @@ -89,7 +90,7 @@ internal ClientSecretCredential(string tenantId, string clientId, string clientS ClientSecret = clientSecret; _allowMultiTenantAuthentication = options?.AllowMultiTenantAuthentication ?? false; _pipeline = pipeline ?? CredentialPipeline.GetInstance(options); - _client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, clientSecret, options as ITokenCacheOptions); + Client = client ?? new MsalConfidentialClient(_pipeline, tenantId, clientId, clientSecret, options as ITokenCacheOptions, (options as ClientSecretCredentialOptions)?.RegionalAuthority); } /// @@ -105,7 +106,7 @@ public override async ValueTask GetTokenAsync(TokenRequestContext r try { var tenantId = TenantIdResolver.Resolve(TenantId, requestContext, _allowMultiTenantAuthentication); - AuthenticationResult result = await _client.AcquireTokenForClientAsync(requestContext.Scopes, tenantId, true, cancellationToken).ConfigureAwait(false); + AuthenticationResult result = await Client.AcquireTokenForClientAsync(requestContext.Scopes, tenantId, true, cancellationToken).ConfigureAwait(false); return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn)); } @@ -128,7 +129,7 @@ public override AccessToken GetToken(TokenRequestContext requestContext, Cancell try { var tenantId = TenantIdResolver.Resolve(TenantId, requestContext, _allowMultiTenantAuthentication); - AuthenticationResult result = _client.AcquireTokenForClientAsync(requestContext.Scopes, tenantId, false, cancellationToken).EnsureCompleted(); + AuthenticationResult result = Client.AcquireTokenForClientAsync(requestContext.Scopes, tenantId, false, cancellationToken).EnsureCompleted(); return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn)); } diff --git a/sdk/identity/Azure.Identity/src/ClientSecretCredentialOptions.cs b/sdk/identity/Azure.Identity/src/ClientSecretCredentialOptions.cs index 68e5c0c204ed..decd5acae968 100644 --- a/sdk/identity/Azure.Identity/src/ClientSecretCredentialOptions.cs +++ b/sdk/identity/Azure.Identity/src/ClientSecretCredentialOptions.cs @@ -12,5 +12,11 @@ public class ClientSecretCredentialOptions : TokenCredentialOptions, ITokenCache /// Specifies the to be used by the credential. If not options are specified, the token cache will not be persisted. /// public TokenCachePersistenceOptions TokenCachePersistenceOptions { get; set; } + + /// + /// Specifies either the specific (preferred), or use to attempt to auto-detect the region. + /// If not specified or auto-detection fails the non-regional endpoint will be used. + /// + public RegionalAuthority? RegionalAuthority { get; set; } = Azure.Identity.RegionalAuthority.FromEnvironment(); } } diff --git a/sdk/identity/Azure.Identity/src/EnvironmentVariables.cs b/sdk/identity/Azure.Identity/src/EnvironmentVariables.cs index d078f80e5af8..a219bceac434 100644 --- a/sdk/identity/Azure.Identity/src/EnvironmentVariables.cs +++ b/sdk/identity/Azure.Identity/src/EnvironmentVariables.cs @@ -27,5 +27,7 @@ internal class EnvironmentVariables public static string ProgramFilesX86 => Environment.GetEnvironmentVariable("ProgramFiles(x86)"); public static string ProgramFiles => Environment.GetEnvironmentVariable("ProgramFiles"); public static string AuthorityHost => Environment.GetEnvironmentVariable("AZURE_AUTHORITY_HOST"); + + public static string AzureRegionalAuthorityName => Environment.GetEnvironmentVariable("AZURE_REGIONAL_AUTHORITY_NAME"); } } diff --git a/sdk/identity/Azure.Identity/src/MsalConfidentialClient.cs b/sdk/identity/Azure.Identity/src/MsalConfidentialClient.cs index cc4f02ec5ed1..00fdbe992713 100644 --- a/sdk/identity/Azure.Identity/src/MsalConfidentialClient.cs +++ b/sdk/identity/Azure.Identity/src/MsalConfidentialClient.cs @@ -19,27 +19,26 @@ internal class MsalConfidentialClient : MsalClientBase protected MsalConfidentialClient() : base() - { } + { + } - public MsalConfidentialClient(CredentialPipeline pipeline, string tenantId, string clientId, string clientSecret, ITokenCacheOptions cacheOptions) + public MsalConfidentialClient(CredentialPipeline pipeline, string tenantId, string clientId, string clientSecret, ITokenCacheOptions cacheOptions, RegionalAuthority? regionalAuthority) : base(pipeline, tenantId, clientId, cacheOptions) { _clientSecret = clientSecret; + RegionalAuthority = regionalAuthority; } - public MsalConfidentialClient( - CredentialPipeline pipeline, - string tenantId, - string clientId, - ClientCertificateCredential.IX509Certificate2Provider certificateProvider, - bool includeX5CClaimHeader, - ITokenCacheOptions cacheOptions) + public MsalConfidentialClient(CredentialPipeline pipeline, string tenantId, string clientId, ClientCertificateCredential.IX509Certificate2Provider certificateProvider, bool includeX5CClaimHeader, ITokenCacheOptions cacheOptions, RegionalAuthority? regionalAuthority) : base(pipeline, tenantId, clientId, cacheOptions) { _includeX5CClaimHeader = includeX5CClaimHeader; _certificateProvider = certificateProvider; + RegionalAuthority = regionalAuthority; } + internal RegionalAuthority? RegionalAuthority { get; } + protected override async ValueTask CreateClientAsync(bool async, CancellationToken cancellationToken) { ConfidentialClientApplicationBuilder confClientBuilder = ConfidentialClientApplicationBuilder.Create(ClientId) @@ -57,6 +56,11 @@ protected override async ValueTask CreateClientA confClientBuilder.WithCertificate(clientCertificate); } + if (RegionalAuthority.HasValue) + { + confClientBuilder.WithAzureRegion(RegionalAuthority.Value.ToString()); + } + return confClientBuilder.Build(); } diff --git a/sdk/identity/Azure.Identity/src/RegionalAuthority.cs b/sdk/identity/Azure.Identity/src/RegionalAuthority.cs new file mode 100644 index 000000000000..1b6c8bda2d6f --- /dev/null +++ b/sdk/identity/Azure.Identity/src/RegionalAuthority.cs @@ -0,0 +1,388 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using Microsoft.Identity.Client; + +namespace Azure.Identity +{ + /// + /// Identifies the regional authority to be used for authentication. + /// + public readonly struct RegionalAuthority : IEquatable + { + internal const string USWestValue = "westus"; + internal const string USWest2Value = "westus2"; + internal const string USCentralValue = "centralus"; + internal const string USEastValue = "eastus"; + internal const string USEast2Value = "eastus2"; + internal const string USNorthCentralValue = "northcentralus"; + internal const string USSouthCentralValue = "southcentralus"; + internal const string USWestCentralValue = "westcentralus"; + internal const string CanadaCentralValue = "canadacentral"; + internal const string CanadaEastValue = "canadaeast"; + internal const string BrazilSouthValue = "brazilsouth"; + internal const string EuropeNorthValue = "northeurope"; + internal const string EuropeWestValue = "westeurope"; + internal const string UKSouthValue = "uksouth"; + internal const string UKWestValue = "ukwest"; + internal const string FranceCentralValue = "francecentral"; + internal const string FranceSouthValue = "francesouth"; + internal const string SwitzerlandNorthValue = "switzerlandnorth"; + internal const string SwitzerlandWestValue = "switzerlandwest"; + internal const string GermanyNorthValue = "germanynorth"; + internal const string GermanyWestCentralValue = "germanywestcentral"; + internal const string NorwayWestValue = "norwaywest"; + internal const string NorwayEastValue = "norwayeast"; + internal const string AsiaEastValue = "eastasia"; + internal const string AsiaSouthEastValue = "southeastasia"; + internal const string JapanEastValue = "japaneast"; + internal const string JapanWestValue = "japanwest"; + internal const string AustraliaEastValue = "australiaeast"; + internal const string AustraliaSouthEastValue = "australiasoutheast"; + internal const string AustraliaCentralValue = "australiacentral"; + internal const string AustraliaCentral2Value = "australiacentral2"; + internal const string IndiaCentralValue = "centralindia"; + internal const string IndiaSouthValue = "southindia"; + internal const string IndiaWestValue = "westindia"; + internal const string KoreaSouthValue = "koreasouth"; + internal const string KoreaCentralValue = "koreacentral"; + internal const string UAECentralValue = "uaecentral"; + internal const string UAENorthValue = "uaenorth"; + internal const string SouthAfricaNorthValue = "southafricanorth"; + internal const string SouthAfricaWestValue = "southafricawest"; + internal const string ChinaNorthValue = "chinanorth"; + internal const string ChinaEastValue = "chinaeast"; + internal const string ChinaNorth2Value = "chinanorth2"; + internal const string ChinaEast2Value = "chinaeast2"; + internal const string GermanyCentralValue = "germanycentral"; + internal const string GermanyNorthEastValue = "germanynortheast"; + internal const string GovernmentUSVirginiaValue = "usgovvirginia"; + internal const string GovernmentUSIowaValue = "usgoviowa"; + internal const string GovernmentUSArizonaValue = "usgovarizona"; + internal const string GovernmentUSTexasValue = "usgovtexas"; + internal const string GovernmentUSDodEastValue = "usdodeast"; + internal const string GovernmentUSDodCentralValue = "usdodcentral"; + + private readonly string _value; + + /// + /// Initializes a new instance of the structure. + /// + /// The string value of the instance. + public RegionalAuthority(string value) + { + _value = value ?? throw new ArgumentNullException(nameof(value)); + } + + /// + /// In cases where the region is not known ahead of time, attempts to automatically discover the appropriate . This works on some azure hosts, such as some VMs (through IDMS), and Azure Functions (using host populated environment variables). + /// If the auto-detection fails, the non-regional authority is used. + /// + public static RegionalAuthority AutoDiscoverRegion { get; } = new RegionalAuthority(ConfidentialClientApplication.AttemptRegionDiscovery); + + /// + /// Uses the for the Azure 'westus' region. + /// + public static RegionalAuthority USWest { get; } = new RegionalAuthority(USWestValue); + + /// + /// Uses the for the Azure 'westus2' region. + /// + public static RegionalAuthority USWest2 { get; } = new RegionalAuthority(USWest2Value); + + /// + /// Uses the for the Azure 'centralus' region. + /// + public static RegionalAuthority USCentral { get; } = new RegionalAuthority(USCentralValue); + + /// + /// Uses the for the Azure 'eastus' region. + /// + public static RegionalAuthority USEast { get; } = new RegionalAuthority(USEastValue); + + /// + /// Uses the for the Azure 'eastus2' region. + /// + public static RegionalAuthority USEast2 { get; } = new RegionalAuthority(USEast2Value); + + /// + /// Uses the for the Azure 'northcentralus' region. + /// + public static RegionalAuthority USNorthCentral { get; } = new RegionalAuthority(USNorthCentralValue); + + /// + /// Uses the for the Azure 'southcentralus' region. + /// + public static RegionalAuthority USSouthCentral { get; } = new RegionalAuthority(USSouthCentralValue); + + /// + /// Uses the for the Azure 'westcentralus' region. + /// + public static RegionalAuthority USWestCentral { get; } = new RegionalAuthority(USWestCentralValue); + + /// + /// Uses the for the Azure 'canadacentral' region. + /// + public static RegionalAuthority CanadaCentral { get; } = new RegionalAuthority(CanadaCentralValue); + + /// + /// Uses the for the Azure 'canadaeast' region. + /// + public static RegionalAuthority CanadaEast { get; } = new RegionalAuthority(CanadaEastValue); + + /// + /// Uses the for the Azure 'brazilsouth' region. + /// + public static RegionalAuthority BrazilSouth { get; } = new RegionalAuthority(BrazilSouthValue); + + /// + /// Uses the for the Azure 'northeurope' region. + /// + public static RegionalAuthority EuropeNorth { get; } = new RegionalAuthority(EuropeNorthValue); + + /// + /// Uses the for the Azure 'westeurope' region. + /// + public static RegionalAuthority EuropeWest { get; } = new RegionalAuthority(EuropeWestValue); + + /// + /// Uses the for the Azure 'uksouth' region. + /// + public static RegionalAuthority UKSouth { get; } = new RegionalAuthority(UKSouthValue); + + /// + /// Uses the for the Azure 'ukwest' region. + /// + public static RegionalAuthority UKWest { get; } = new RegionalAuthority(UKWestValue); + + /// + /// Uses the for the Azure 'francecentral' region. + /// + public static RegionalAuthority FranceCentral { get; } = new RegionalAuthority(FranceCentralValue); + + /// + /// Uses the for the Azure 'francesouth' region. + /// + public static RegionalAuthority FranceSouth { get; } = new RegionalAuthority(FranceSouthValue); + + /// + /// Uses the for the Azure 'switzerlandnorth' region. + /// + public static RegionalAuthority SwitzerlandNorth { get; } = new RegionalAuthority(SwitzerlandNorthValue); + + /// + /// Uses the for the Azure 'switzerlandwest' region. + /// + public static RegionalAuthority SwitzerlandWest { get; } = new RegionalAuthority(SwitzerlandWestValue); + + /// + /// Uses the for the Azure 'germanynorth' region. + /// + public static RegionalAuthority GermanyNorth { get; } = new RegionalAuthority(GermanyNorthValue); + + /// + /// Uses the for the Azure 'germanywestcentral' region. + /// + public static RegionalAuthority GermanyWestCentral { get; } = new RegionalAuthority(GermanyWestCentralValue); + + /// + /// Uses the for the Azure 'norwaywest' region. + /// + public static RegionalAuthority NorwayWest { get; } = new RegionalAuthority(NorwayWestValue); + + /// + /// Uses the for the Azure 'norwayeast' region. + /// + public static RegionalAuthority NorwayEast { get; } = new RegionalAuthority(NorwayEastValue); + + /// + /// Uses the for the Azure 'eastasia' region. + /// + public static RegionalAuthority AsiaEast { get; } = new RegionalAuthority(AsiaEastValue); + + /// + /// Uses the for the Azure 'southeastasia' region. + /// + public static RegionalAuthority AsiaSouthEast { get; } = new RegionalAuthority(AsiaSouthEastValue); + + /// + /// Uses the for the Azure 'japaneast' region. + /// + public static RegionalAuthority JapanEast { get; } = new RegionalAuthority(JapanEastValue); + + /// + /// Uses the for the Azure 'japanwest' region. + /// + public static RegionalAuthority JapanWest { get; } = new RegionalAuthority(JapanWestValue); + + /// + /// Uses the for the Azure 'australiaeast' region. + /// + public static RegionalAuthority AustraliaEast { get; } = new RegionalAuthority(AustraliaEastValue); + + /// + /// Uses the for the Azure 'australiasoutheast' region. + /// + public static RegionalAuthority AustraliaSouthEast { get; } = new RegionalAuthority(AustraliaSouthEastValue); + + /// + /// Uses the for the Azure 'australiacentral' region. + /// + public static RegionalAuthority AustraliaCentral { get; } = new RegionalAuthority(AustraliaCentralValue); + + /// + /// Uses the for the Azure 'australiacentral2' region. + /// + public static RegionalAuthority AustraliaCentral2 { get; } = new RegionalAuthority(AustraliaCentral2Value); + + /// + /// Uses the for the Azure 'centralindia' region. + /// + public static RegionalAuthority IndiaCentral { get; } = new RegionalAuthority(IndiaCentralValue); + + /// + /// Uses the for the Azure 'southindia' region. + /// + public static RegionalAuthority IndiaSouth { get; } = new RegionalAuthority(IndiaSouthValue); + + /// + /// Uses the for the Azure 'westindia' region. + /// + public static RegionalAuthority IndiaWest { get; } = new RegionalAuthority(IndiaWestValue); + + /// + /// Uses the for the Azure 'koreasouth' region. + /// + public static RegionalAuthority KoreaSouth { get; } = new RegionalAuthority(KoreaSouthValue); + + /// + /// Uses the for the Azure 'koreacentral' region. + /// + public static RegionalAuthority KoreaCentral { get; } = new RegionalAuthority(KoreaCentralValue); + + /// + /// Uses the for the Azure 'uaecentral' region. + /// + public static RegionalAuthority UAECentral { get; } = new RegionalAuthority(UAECentralValue); + + /// + /// Uses the for the Azure 'uaenorth' region. + /// + public static RegionalAuthority UAENorth { get; } = new RegionalAuthority(UAENorthValue); + + /// + /// Uses the for the Azure 'southafricanorth' region. + /// + public static RegionalAuthority SouthAfricaNorth { get; } = new RegionalAuthority(SouthAfricaNorthValue); + + /// + /// Uses the for the Azure 'southafricawest' region. + /// + public static RegionalAuthority SouthAfricaWest { get; } = new RegionalAuthority(SouthAfricaWestValue); + + /// + /// Uses the for the Azure 'chinanorth' region. + /// + public static RegionalAuthority ChinaNorth { get; } = new RegionalAuthority(ChinaNorthValue); + + /// + /// Uses the for the Azure 'chinaeast' region. + /// + public static RegionalAuthority ChinaEast { get; } = new RegionalAuthority(ChinaEastValue); + + /// + /// Uses the for the Azure 'chinanorth2' region. + /// + public static RegionalAuthority ChinaNorth2 { get; } = new RegionalAuthority(ChinaNorth2Value); + + /// + /// Uses the for the Azure 'chinaeast2' region. + /// + public static RegionalAuthority ChinaEast2 { get; } = new RegionalAuthority(ChinaEast2Value); + + /// + /// Uses the for the Azure 'germanycentral' region. + /// + public static RegionalAuthority GermanyCentral { get; } = new RegionalAuthority(GermanyCentralValue); + + /// + /// Uses the for the Azure 'germanynortheast' region. + /// + public static RegionalAuthority GermanyNorthEast { get; } = new RegionalAuthority(GermanyNorthEastValue); + + /// + /// Uses the for the Azure 'usgovvirginia' region. + /// + public static RegionalAuthority GovernmentUSVirginia { get; } = new RegionalAuthority(GovernmentUSVirginiaValue); + + /// + /// Uses the for the Azure 'usgoviowa' region. + /// + public static RegionalAuthority GovernmentUSIowa { get; } = new RegionalAuthority(GovernmentUSIowaValue); + + /// + /// Uses the for the Azure 'usgovarizona' region. + /// + public static RegionalAuthority GovernmentUSArizona { get; } = new RegionalAuthority(GovernmentUSArizonaValue); + + /// + /// Uses the for the Azure 'usgovtexas' region. + /// + public static RegionalAuthority GovernmentUSTexas { get; } = new RegionalAuthority(GovernmentUSTexasValue); + + /// + /// Uses the for the Azure 'usdodeast' region. + /// + public static RegionalAuthority GovernmentUSDodEast { get; } = new RegionalAuthority(GovernmentUSDodEastValue); + + /// + /// Uses the for the Azure 'usdodcentral' region. + /// + public static RegionalAuthority GovernmentUSDodCentral { get; } = new RegionalAuthority(GovernmentUSDodCentralValue); + + /// + /// Determines if two values are the same. + /// + /// The first to compare. + /// The second to compare. + /// True if and are the same; otherwise, false. + public static bool operator ==(RegionalAuthority left, RegionalAuthority right) => left.Equals(right); + + /// + /// Determines if two values are different. + /// + /// The first to compare. + /// The second to compare. + /// True if and are different; otherwise, false. + public static bool operator !=(RegionalAuthority left, RegionalAuthority right) => !left.Equals(right); + + /// + /// Converts a string to a . + /// + /// The string value to convert. + public static implicit operator RegionalAuthority(string value) => new RegionalAuthority(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is RegionalAuthority other && Equals(other); + + /// + public bool Equals(RegionalAuthority other) => string.Equals(_value, other._value, StringComparison.Ordinal); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value?.GetHashCode() ?? 0; + + /// + public override string ToString() => _value; + + internal static RegionalAuthority? FromEnvironment() + { + return string.IsNullOrEmpty(EnvironmentVariables.AzureRegionalAuthorityName) ? (RegionalAuthority?)null : new RegionalAuthority(EnvironmentVariables.AzureRegionalAuthorityName); + } + } +} diff --git a/sdk/identity/Azure.Identity/tests/ClientCertificateCredentialTests.cs b/sdk/identity/Azure.Identity/tests/ClientCertificateCredentialTests.cs index 40d91bb20056..fbd7f9fdd15d 100644 --- a/sdk/identity/Azure.Identity/tests/ClientCertificateCredentialTests.cs +++ b/sdk/identity/Azure.Identity/tests/ClientCertificateCredentialTests.cs @@ -200,10 +200,31 @@ public void TestSetup() Func clientFactory = (_, _tenantId) => { - Assert.AreEqual(expectedTenantId, _tenantId); return result; }; mockMsalClient = new MockMsalConfidentialClient(clientFactory); } + + private static IEnumerable RegionalAuthorityTestData() + { + yield return new TestCaseData(null); + yield return new TestCaseData(RegionalAuthority.AutoDiscoverRegion); + yield return new TestCaseData(RegionalAuthority.USWest); + } + + [Test] + [TestCaseSource("RegionalAuthorityTestData")] + public void VerifyMsalClientRegionalAuthority(RegionalAuthority? regionalAuthority) + { + var expectedTenantId = Guid.NewGuid().ToString(); + + var expectedClientId = Guid.NewGuid().ToString(); + + var certificatePath = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "cert.pfx"); + + var cred = new ClientCertificateCredential(expectedTenantId, expectedClientId, certificatePath, new ClientCertificateCredentialOptions { RegionalAuthority = regionalAuthority }); + + Assert.AreEqual(regionalAuthority, cred.Client.RegionalAuthority); + } } } diff --git a/sdk/identity/Azure.Identity/tests/ClientSecretCredentialLiveTests.cs b/sdk/identity/Azure.Identity/tests/ClientSecretCredentialLiveTests.cs index fe4d759f6cde..37be4de07954 100644 --- a/sdk/identity/Azure.Identity/tests/ClientSecretCredentialLiveTests.cs +++ b/sdk/identity/Azure.Identity/tests/ClientSecretCredentialLiveTests.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using System; +using System.Collections.Generic; using System.Threading.Tasks; using Azure.Core; using Azure.Core.TestFramework; @@ -97,5 +98,27 @@ protected internal override Task TokenCacheUpdatedAsync(TokenCacheUpdatedArgs to return Task.CompletedTask; } } + + private static IEnumerable RegionalAuthorityTestData() + { + yield return new TestCaseData(null); + yield return new TestCaseData(RegionalAuthority.AutoDiscoverRegion); + yield return new TestCaseData(RegionalAuthority.USWest); + } + + [Test] + [TestCaseSource("RegionalAuthorityTestData")] + public void VerifyMsalClientRegionalAuthority(RegionalAuthority? regionalAuthority) + { + var expectedTenantId = Guid.NewGuid().ToString(); + + var expectedClientId = Guid.NewGuid().ToString(); + + var expectedClientSecret = Guid.NewGuid().ToString(); + + var cred = new ClientSecretCredential(expectedTenantId, expectedClientId, expectedClientSecret, new ClientSecretCredentialOptions { RegionalAuthority = regionalAuthority }); + + Assert.AreEqual(regionalAuthority, cred.Client.RegionalAuthority); + } } }