Skip to content

Commit cd459f6

Browse files
bgavrilMSgladjohn
andauthored
Opt-in to regional when env variable MSAL_FORCE_REGION is set (#4954)
Co-authored-by: Gladwin Johnson <[email protected]>
1 parent 97c51de commit cd459f6

File tree

2 files changed

+112
-6
lines changed

2 files changed

+112
-6
lines changed

src/client/Microsoft.Identity.Client/AppConfig/ConfidentialClientApplicationBuilder.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@
99
using System.Threading;
1010
using System.Threading.Tasks;
1111
using Microsoft.Identity.Client.AppConfig;
12-
using Microsoft.Identity.Client.Extensibility;
1312
using Microsoft.Identity.Client.Instance;
1413
using Microsoft.Identity.Client.Internal;
1514
using Microsoft.Identity.Client.Internal.ClientCredential;
16-
using Microsoft.Identity.Client.TelemetryCore;
17-
using Microsoft.Identity.Client.TelemetryCore.TelemetryClient;
1815
using Microsoft.IdentityModel.Abstractions;
1916

2017
namespace Microsoft.Identity.Client
@@ -26,6 +23,9 @@ namespace Microsoft.Identity.Client
2623
#endif
2724
public class ConfidentialClientApplicationBuilder : AbstractApplicationBuilder<ConfidentialClientApplicationBuilder>
2825
{
26+
internal const string ForceRegionEnvVariable = "MSAL_FORCE_REGION";
27+
internal const string DisableForceRegion = "DisableMsalForceRegion";
28+
2929
/// <inheritdoc/>
3030
internal ConfidentialClientApplicationBuilder(ApplicationConfiguration configuration)
3131
: base(configuration)
@@ -380,10 +380,25 @@ internal override void Validate()
380380
throw new InvalidOperationException(MsalErrorMessage.InvalidRedirectUriReceived(Config.RedirectUri));
381381
}
382382

383-
if (!string.IsNullOrEmpty(Config.AzureRegion) && (Config.CustomInstanceDiscoveryMetadata != null || Config.CustomInstanceDiscoveryMetadataUri != null))
383+
if (!string.IsNullOrEmpty(Config.AzureRegion) &&
384+
(Config.CustomInstanceDiscoveryMetadata != null || Config.CustomInstanceDiscoveryMetadataUri != null))
384385
{
385386
throw new MsalClientException(MsalError.RegionDiscoveryWithCustomInstanceMetadata, MsalErrorMessage.RegionDiscoveryWithCustomInstanceMetadata);
386387
}
388+
389+
// use regional if MSAL_FORCE_REGION is used, as per #4930
390+
if (string.Equals(Config.AzureRegion, DisableForceRegion, StringComparison.OrdinalIgnoreCase))
391+
{
392+
Config.AzureRegion = null;
393+
}
394+
else if (Config.AzureRegion == null)
395+
{
396+
string forcedRegion = Environment.GetEnvironmentVariable(ForceRegionEnvVariable);
397+
if (!string.IsNullOrEmpty(forcedRegion))
398+
{
399+
Config.AzureRegion = forcedRegion;
400+
}
401+
}
387402
}
388403

389404
/// <summary>

tests/Microsoft.Identity.Test.Unit/PublicApiTests/ClientCredentialWithRegionTests.cs

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
#if !ANDROID && !iOS
54
using System;
65
using System.IO;
76
using System.Net;
@@ -304,6 +303,99 @@ public async Task RegionFallbackToGlobalAsync()
304303
}
305304
}
306305

306+
[TestMethod]
307+
public async Task MsalForceRegionIsSet_RegionIsUsed()
308+
{
309+
using (new EnvVariableContext())
310+
using (var httpManager = new MockHttpManager())
311+
{
312+
Environment.SetEnvironmentVariable(
313+
ConfidentialClientApplicationBuilder.ForceRegionEnvVariable, TestConstants.Region);
314+
315+
httpManager.AddRegionDiscoveryMockHandler(TestConstants.Region);
316+
httpManager.AddMockHandler(CreateTokenResponseHttpHandler(expectRegional: true));
317+
318+
var cca = ConfidentialClientApplicationBuilder
319+
.Create(TestConstants.ClientId)
320+
.WithHttpManager(httpManager)
321+
.WithClientSecret(TestConstants.ClientSecret)
322+
.Build();
323+
324+
AuthenticationResult result = await cca
325+
.AcquireTokenForClient(TestConstants.s_scope)
326+
.ExecuteAsync()
327+
.ConfigureAwait(false);
328+
329+
Assert.AreEqual(TestConstants.Region, result.ApiEvent.RegionUsed);
330+
Assert.AreEqual(RegionAutodetectionSource.Imds, result.ApiEvent.RegionAutodetectionSource);
331+
332+
Assert.AreEqual(TestConstants.Region, result.AuthenticationResultMetadata.RegionDetails.RegionUsed);
333+
Assert.AreEqual(RegionOutcome.UserProvidedValid, result.AuthenticationResultMetadata.RegionDetails.RegionOutcome);
334+
Assert.IsNull(result.AuthenticationResultMetadata.RegionDetails.AutoDetectionError);
335+
}
336+
}
337+
338+
[TestMethod]
339+
public async Task MsalForceRegionIsSet_WithRegionIsSet_WithRegionWins()
340+
{
341+
using (new EnvVariableContext())
342+
using (var httpManager = new MockHttpManager())
343+
{
344+
// this will be ignored, in favor of TestConstants.Region
345+
Environment.SetEnvironmentVariable(
346+
ConfidentialClientApplicationBuilder.ForceRegionEnvVariable, "someOtherRegion");
347+
348+
httpManager.AddRegionDiscoveryMockHandler(TestConstants.Region);
349+
httpManager.AddMockHandler(CreateTokenResponseHttpHandler(expectRegional: true));
350+
351+
var cca = ConfidentialClientApplicationBuilder
352+
.Create(TestConstants.ClientId)
353+
.WithHttpManager(httpManager)
354+
.WithAzureRegion(TestConstants.Region)
355+
.WithClientSecret(TestConstants.ClientSecret)
356+
.Build();
357+
358+
AuthenticationResult result = await cca
359+
.AcquireTokenForClient(TestConstants.s_scope)
360+
.ExecuteAsync()
361+
.ConfigureAwait(false);
362+
363+
Assert.AreEqual(TestConstants.Region, result.ApiEvent.RegionUsed);
364+
Assert.AreEqual(RegionAutodetectionSource.Imds, result.ApiEvent.RegionAutodetectionSource);
365+
366+
Assert.AreEqual(TestConstants.Region, result.AuthenticationResultMetadata.RegionDetails.RegionUsed);
367+
Assert.AreEqual(RegionOutcome.UserProvidedValid, result.AuthenticationResultMetadata.RegionDetails.RegionOutcome);
368+
Assert.IsNull(result.AuthenticationResultMetadata.RegionDetails.AutoDetectionError);
369+
}
370+
}
371+
372+
[TestMethod]
373+
public async Task MsalForceRegionIsSet_WithRegionIsSetToOptOut_NoRegionIsUsed()
374+
{
375+
using (new EnvVariableContext())
376+
using (var httpManager = new MockHttpManager())
377+
{
378+
Environment.SetEnvironmentVariable(
379+
ConfidentialClientApplicationBuilder.ForceRegionEnvVariable, TestConstants.Region);
380+
381+
httpManager.AddInstanceDiscoveryMockHandler();
382+
httpManager.AddMockHandler(CreateTokenResponseHttpHandler(expectRegional: false));
383+
384+
var cca = ConfidentialClientApplicationBuilder
385+
.Create(TestConstants.ClientId)
386+
.WithHttpManager(httpManager)
387+
.WithAzureRegion(ConfidentialClientApplicationBuilder.DisableForceRegion)
388+
.WithClientSecret(TestConstants.ClientSecret)
389+
.Build();
390+
391+
AuthenticationResult result = await cca
392+
.AcquireTokenForClient(TestConstants.s_scope)
393+
.ExecuteAsync()
394+
.ConfigureAwait(false);
395+
396+
Assert.IsNull(result.ApiEvent.RegionUsed);
397+
}
398+
}
307399
[TestMethod]
308400
public void WithAzureRegionThrowsOnNullArg()
309401
{
@@ -724,4 +816,3 @@ private static HttpResponseMessage CreateResponse(bool clientCredentialFlow)
724816

725817
}
726818
}
727-
#endif

0 commit comments

Comments
 (0)