diff --git a/Directory.Build.props b/Directory.Build.props index d0329f258..d8f120410 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -80,8 +80,8 @@ 8.19.1 - 4.85.2 - 4.85.2 + 4.86.0 + 4.86.0 12.4.0 3.3.0 4.7.2 diff --git a/src/Microsoft.Identity.Web.TokenAcquisition/AcquireTokenResultFactory.cs b/src/Microsoft.Identity.Web.TokenAcquisition/AcquireTokenResultFactory.cs index 6bf2c86b6..94fbab79c 100644 --- a/src/Microsoft.Identity.Web.TokenAcquisition/AcquireTokenResultFactory.cs +++ b/src/Microsoft.Identity.Web.TokenAcquisition/AcquireTokenResultFactory.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. using Microsoft.Identity.Client; +using Microsoft.Identity.Client.Region; using Abstractions = Microsoft.Identity.Abstractions; namespace Microsoft.Identity.Web @@ -65,8 +66,15 @@ public static Abstractions.AcquireTokenResult FromMsal(AuthenticationResult resu source is null ? null : new Abstractions.AcquiredTokenRegionDetails { RegionUsed = source.RegionUsed, - RegionOutcome = (Abstractions.AcquiredTokenRegionOutcome)source.RegionOutcome, + RegionOutcome = MapRegionOutcome(source.RegionOutcome), AutoDetectionError = source.AutoDetectionError, }; + + private static Abstractions.AcquiredTokenRegionOutcome MapRegionOutcome(RegionOutcome regionOutcome) => + regionOutcome switch + { + RegionOutcome.UserProvided => Abstractions.AcquiredTokenRegionOutcome.UserProvidedValid, + _ => (Abstractions.AcquiredTokenRegionOutcome)regionOutcome, + }; } } diff --git a/tests/Microsoft.Identity.Web.Test/AcquireTokenResultFactoryEnumRoundTripTests.cs b/tests/Microsoft.Identity.Web.Test/AcquireTokenResultFactoryEnumRoundTripTests.cs index a82a891db..f478817ec 100644 --- a/tests/Microsoft.Identity.Web.Test/AcquireTokenResultFactoryEnumRoundTripTests.cs +++ b/tests/Microsoft.Identity.Web.Test/AcquireTokenResultFactoryEnumRoundTripTests.cs @@ -12,10 +12,10 @@ namespace Microsoft.Identity.Web.Test { /// /// Pins the numeric lockstep between MSAL enums and their Abstractions counterparts. - /// casts MSAL enum values directly - /// to Abstractions enum values. If MSAL ever renumbers a member or adds a new one - /// out of order, these tests will fail loudly instead of producing silently-wrong - /// telemetry. One assertion per member of every casted enum. + /// maps MSAL enum values to their Abstractions + /// counterparts. If MSAL ever renumbers a member or adds a new one out of order, + /// these tests will fail loudly instead of producing silently-wrong telemetry. + /// One assertion per member of every casted enum. /// public class AcquireTokenResultFactoryEnumRoundTripTests { @@ -54,15 +54,15 @@ public void CacheLevel_NumericCast_RoundTrips(CacheLevel msal, Abstractions.Acqu } [Theory] - [InlineData(RegionOutcome.None, Abstractions.AcquiredTokenRegionOutcome.None)] - [InlineData(RegionOutcome.UserProvidedValid, Abstractions.AcquiredTokenRegionOutcome.UserProvidedValid)] - [InlineData(RegionOutcome.UserProvidedAutodetectionFailed, Abstractions.AcquiredTokenRegionOutcome.UserProvidedAutodetectionFailed)] - [InlineData(RegionOutcome.UserProvidedInvalid, Abstractions.AcquiredTokenRegionOutcome.UserProvidedInvalid)] - [InlineData(RegionOutcome.AutodetectSuccess, Abstractions.AcquiredTokenRegionOutcome.AutodetectSuccess)] - [InlineData(RegionOutcome.FallbackToGlobal, Abstractions.AcquiredTokenRegionOutcome.FallbackToGlobal)] - public void RegionOutcome_NumericCast_RoundTrips(RegionOutcome msal, Abstractions.AcquiredTokenRegionOutcome expected) + [InlineData((int)RegionOutcome.None, Abstractions.AcquiredTokenRegionOutcome.None)] + [InlineData(1, Abstractions.AcquiredTokenRegionOutcome.UserProvidedValid)] + [InlineData(2, Abstractions.AcquiredTokenRegionOutcome.UserProvidedAutodetectionFailed)] + [InlineData(3, Abstractions.AcquiredTokenRegionOutcome.UserProvidedInvalid)] + [InlineData((int)RegionOutcome.AutodetectSuccess, Abstractions.AcquiredTokenRegionOutcome.AutodetectSuccess)] + [InlineData((int)RegionOutcome.FallbackToGlobal, Abstractions.AcquiredTokenRegionOutcome.FallbackToGlobal)] + public void RegionOutcome_NumericCast_RoundTrips(int msal, Abstractions.AcquiredTokenRegionOutcome expected) { - Assert.Equal((int)expected, (int)msal); + Assert.Equal((int)expected, msal); Assert.Equal(expected, (Abstractions.AcquiredTokenRegionOutcome)msal); } @@ -88,7 +88,7 @@ public void EnumMemberCounts_MatchAbstractions() System.Enum.GetValues(typeof(Abstractions.AcquiredTokenCacheLevel)).Length); Assert.Equal( - System.Enum.GetValues(typeof(RegionOutcome)).Length, + System.Enum.GetValues(typeof(RegionOutcome)).Length - 1, System.Enum.GetValues(typeof(Abstractions.AcquiredTokenRegionOutcome)).Length); } @@ -126,6 +126,40 @@ public void GetMetadata_SetsExpiresOn_FromResult_WhenMetadataAvailable() Assert.Equal(refreshOn, metadata.RefreshOn); } + [Fact] + public void GetMetadata_MapsUserProvidedRegionOutcome_ToStableAbstractionsOutcome() + { + // Arrange + const string region = "westus2"; + DateTimeOffset expiresOn = DateTimeOffset.UtcNow.AddHours(1); + DateTimeOffset extendedExpiresOn = DateTimeOffset.UtcNow.AddHours(2); + var source = new AuthenticationResultMetadata(TokenSource.IdentityProvider) + { + RegionDetails = new RegionDetails(RegionOutcome.UserProvided, region, string.Empty), + }; + var result = new AuthenticationResult( + "access-token", + false, + null, + expiresOn, + extendedExpiresOn, + "tenant", + null, + null, + new[] { "scope" }, + Guid.NewGuid(), + source); + + // Act + Abstractions.TokenAcquisitionMetadata? metadata = AcquireTokenResultFactory.GetMetadata(result); + + // Assert + Assert.NotNull(metadata); + Assert.NotNull(metadata!.RegionDetails); + Assert.Equal(region, metadata.RegionDetails!.RegionUsed); + Assert.Equal(Abstractions.AcquiredTokenRegionOutcome.UserProvidedValid, metadata.RegionDetails.RegionOutcome); + } + [Fact] public void GetMetadata_ReturnsNull_WhenMetadataAbsent() {