Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,46 +78,45 @@ public async Task<string> GetAzureRegionAsync(RequestContext requestContext)
requestContext.ApiEvent != null,
"Do not call GetAzureRegionAsync outside of a request. This can happen if you perform instance discovery outside a request, for example as part of validating input params.");

if (!IsAutoDiscoveryRequested(azureRegionConfig))
Comment thread
4gust marked this conversation as resolved.
{
// For a user-provided region (WithAzureRegion or the MSAL_FORCE_REGION env variable),
// validate the format before using it. An invalid region (e.g. one containing a host,
// path, or other special characters) must never be prefixed onto the trusted
// "{region}.login.microsoft.com" suffix, as that would redirect the request to a
// tampered host. Consistent with region handling elsewhere, an invalid value falls
// back to the global (non-regional) endpoint rather than failing the request.
if (!IsValidRegionName(azureRegionConfig))
{
logger.Error($"[Region discovery] User provided region '{azureRegionConfig}' is invalid. Falling back to the global endpoint. {DateTime.UtcNow}");
return null;
}
Comment thread
4gust marked this conversation as resolved.

logger.Info(() => $"[Region discovery] Returning user provided region: {azureRegionConfig}.");
requestContext.ApiEvent.RegionUsed = azureRegionConfig;
return azureRegionConfig;
Comment thread
4gust marked this conversation as resolved.
}

IRetryPolicyFactory retryPolicyFactory = requestContext.ServiceBundle.Config.RetryPolicyFactory;
IRetryPolicy retryPolicy = retryPolicyFactory.GetRetryPolicy(RequestType.RegionDiscovery);

// MSAL always performs region auto-discovery, even if the user configured an actual region
// in order to detect inconsistencies and report via telemetry
var discoveredRegion = await DiscoverAndCacheAsync(logger, requestContext.UserCancellationToken, retryPolicy).ConfigureAwait(false);

RecordTelemetry(requestContext.ApiEvent, azureRegionConfig, discoveredRegion);

if (IsAutoDiscoveryRequested(azureRegionConfig))
if (discoveredRegion.RegionSource != RegionAutodetectionSource.FailedAutoDiscovery)
{
if (discoveredRegion.RegionSource != RegionAutodetectionSource.FailedAutoDiscovery)
{
logger.Verbose(() => $"[Region discovery] Discovered Region {discoveredRegion.Region}");
requestContext.ApiEvent.RegionUsed = discoveredRegion.Region;
requestContext.ApiEvent.AutoDetectedRegion = discoveredRegion.Region;
return discoveredRegion.Region;
}
else
{
logger.Verbose(() => $"[Region discovery] {s_regionDiscoveryDetails}");
requestContext.ApiEvent.RegionDiscoveryFailureReason = s_regionDiscoveryDetails;
return null;
}
logger.Verbose(() => $"[Region discovery] Discovered Region {discoveredRegion.Region}");
requestContext.ApiEvent.RegionUsed = discoveredRegion.Region;
requestContext.ApiEvent.AutoDetectedRegion = discoveredRegion.Region;
return discoveredRegion.Region;
}

// For a user-provided region (WithAzureRegion or the MSAL_FORCE_REGION env variable),
// validate the format before using it. An invalid region (e.g. one containing a host,
// path, or other special characters) must never be prefixed onto the trusted
// "{region}.login.microsoft.com" suffix, as that would redirect the request to a
// tampered host. Consistent with region handling elsewhere, an invalid value falls
// back to the global (non-regional) endpoint rather than failing the request.
if (!IsValidRegionName(azureRegionConfig))
else
{
logger.Error($"[Region discovery] User provided region '{azureRegionConfig}' is invalid. Falling back to the global endpoint. {DateTime.UtcNow}");
logger.Verbose(() => $"[Region discovery] {s_regionDiscoveryDetails}");
requestContext.ApiEvent.RegionDiscoveryFailureReason = s_regionDiscoveryDetails;
return null;
}

logger.Info(() => $"[Region discovery] Returning user provided region: {azureRegionConfig}.");
return azureRegionConfig;
}

internal static void ResetStaticCacheForTest()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,18 +197,8 @@ public async Task FetchRegionFromLocalImdsThenGetMetadataFromCacheAsync()
}

[TestMethod]
[DataRow(HttpStatusCode.NotFound, 0, TestConstants.RegionAutoDetectNotFoundFailureMessage)] // No retries for 404 errors
[DataRow(HttpStatusCode.InternalServerError, TestRegionDiscoveryRetryPolicy.NumRetries, TestConstants.RegionAutoDetectInternalServerErrorFailureMessage)]
public async Task SuccessfulResponseFromUserProvidedRegionAsync(
HttpStatusCode statusCode,
int expectedRetries,
string expectedFailureMessage)
public async Task SuccessfulResponseFromUserProvidedRegionDoesNotCallImdsAsync()
{
for (int i = 0; i < (1 + expectedRetries); i++)
{
AddMockedResponse(MockHelpers.CreateNullMessage(statusCode));
}

_testRequestContext.ServiceBundle.Config.AzureRegion = TestConstants.Region;
RegionManager.ResetStaticCacheForTest();
IRegionDiscoveryProvider regionDiscoveryProvider = new RegionAndMtlsDiscoveryProvider(_httpManager);
Expand All @@ -219,16 +209,16 @@ public async Task SuccessfulResponseFromUserProvidedRegionAsync(
Assert.AreEqual($"centralus.{RegionAndMtlsDiscoveryProvider.PublicEnvForRegional}", regionalMetadata.PreferredNetwork);

Assert.AreEqual(TestConstants.Region, _testRequestContext.ApiEvent.RegionUsed);
Assert.AreEqual(RegionAutodetectionSource.FailedAutoDiscovery, _testRequestContext.ApiEvent.RegionAutodetectionSource);
Assert.AreEqual(RegionOutcome.UserProvidedAutodetectionFailed, _testRequestContext.ApiEvent.RegionOutcome);
Assert.Contains(expectedFailureMessage, _testRequestContext.ApiEvent.RegionDiscoveryFailureReason);
Assert.AreEqual(RegionAutodetectionSource.None, _testRequestContext.ApiEvent.RegionAutodetectionSource);
Assert.AreEqual(RegionOutcome.None, _testRequestContext.ApiEvent.RegionOutcome);
Comment thread
4gust marked this conversation as resolved.
Outdated
Assert.IsNull(_testRequestContext.ApiEvent.RegionDiscoveryFailureReason);

// Verify all mock responses were consumed
// Verify no IMDS request was made for the explicit region.
Assert.AreEqual(0, _httpManager.QueueSize);
}

[TestMethod]
public async Task ResponseFromUserProvidedRegionSameAsRegionDetectedAsync()
public async Task ResponseFromUserProvidedRegionSkipsEnvDetectionAsync()
Comment thread
4gust marked this conversation as resolved.
Outdated
{
Environment.SetEnvironmentVariable(TestConstants.RegionName, TestConstants.Region);
_testRequestContext.ServiceBundle.Config.AzureRegion = TestConstants.Region;
Expand All @@ -239,13 +229,13 @@ public async Task ResponseFromUserProvidedRegionSameAsRegionDetectedAsync()
Assert.IsNotNull(regionalMetadata);
Assert.AreEqual($"centralus.{RegionAndMtlsDiscoveryProvider.PublicEnvForRegional}", regionalMetadata.PreferredNetwork);
Assert.AreEqual(TestConstants.Region, _testRequestContext.ApiEvent.RegionUsed);
Assert.AreEqual(RegionAutodetectionSource.EnvVariable, _testRequestContext.ApiEvent.RegionAutodetectionSource);
Assert.AreEqual(RegionOutcome.UserProvidedValid, _testRequestContext.ApiEvent.RegionOutcome);
Assert.AreEqual(RegionAutodetectionSource.None, _testRequestContext.ApiEvent.RegionAutodetectionSource);
Assert.AreEqual(RegionOutcome.None, _testRequestContext.ApiEvent.RegionOutcome);
Assert.IsNull(_testRequestContext.ApiEvent.RegionDiscoveryFailureReason);
}

[TestMethod]
public async Task ResponseFromUserProvidedRegionDifferentFromRegionDetectedAsync()
public async Task ResponseFromUserProvidedRegionSkipsRegionMismatchDetectionAsync()
{
Environment.SetEnvironmentVariable(TestConstants.RegionName, "detectedregion");
_testRequestContext.ServiceBundle.Config.AzureRegion = "userregion";
Expand All @@ -258,8 +248,8 @@ public async Task ResponseFromUserProvidedRegionDifferentFromRegionDetectedAsync
Assert.IsNotNull(regionalMetadata);
Assert.AreEqual($"userregion.{RegionAndMtlsDiscoveryProvider.PublicEnvForRegional}", regionalMetadata.PreferredNetwork);
Assert.AreEqual("userregion", _testRequestContext.ApiEvent.RegionUsed);
Assert.AreEqual(RegionAutodetectionSource.EnvVariable, _testRequestContext.ApiEvent.RegionAutodetectionSource);
Assert.AreEqual(RegionOutcome.UserProvidedInvalid, _testRequestContext.ApiEvent.RegionOutcome);
Assert.AreEqual(RegionAutodetectionSource.None, _testRequestContext.ApiEvent.RegionAutodetectionSource);
Assert.AreEqual(RegionOutcome.None, _testRequestContext.ApiEvent.RegionOutcome);
Assert.IsNull(_testRequestContext.ApiEvent.RegionDiscoveryFailureReason);
}

Expand Down
Loading
Loading