Skip to content

Commit d0f3d8d

Browse files
authored
CP -> releases/2.0.2 Fix silent auth failure in WSL caused by broker token provider (#675) (#676)
WSL reports as Linux but has no msalruntime daemon, causing MsalSilentTokenProvider to fail when using appInteractiveBroker. - Add PlatformInformation.IsWSL() to detect WSL via RuntimeInformation.IsOSPlatform(Linux) and WSL_DISTRO_NAME env var - Use non-broker app for silent auth on WSL, matching behavior before 0cddac6 - Add tests for WSL and non-WSL silent auth provider selection ### Problem Commit #664 (#666) changed `MsalSilentTokenProvidert`o use `appInteractiveBroker ?? app` so that the broker's token cache is queried on silent auth. This works correctly on Windows and macOS, but breaks Windows Subsystem for Linux (WSL) due to stdout corruption from MSAL linux broker subprocesses. Related MSAL issue: AzureAD/microsoft-authentication-library-for-dotnet#5979 ### work around until MSAL responds Add `PlatformInformation.IsWSL()` which returns true when the runtime OS is Linux and the WSL_DISTRO_NAME environment variable is set (always present in WSL sessions, never set on native Linux/macOS/Windows). In `MsalTokenProviders.Get()` use the non-broker app for silent auth when running in WSL, restoring the pre-#664 behavior for WSL users while keeping broker-accelerated silent auth on Windows and macOS. ### Testing Added unit tests covering silent provider selection under WSL and non-WSL conditions with both empty and warm MSAL caches.
1 parent 7f144f1 commit d0f3d8d

3 files changed

Lines changed: 59 additions & 3 deletions

File tree

src/Authentication.Tests/TokenProviderTests.cs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,14 @@ public void MsalManagedIdentityContractTest()
177177
}
178178

179179
[TestMethod]
180-
public async Task MsalTokenProviders_SilentProvider_UsesBrokerApp_WhenProvided()
180+
public async Task MsalTokenProviders_SilentProvider_UsesBrokerApp_WhenProvided_NonWSL()
181181
{
182+
if (PlatformInformation.IsWSL())
183+
{
184+
// On WSL the broker app is intentionally skipped for silent auth; see the WSL test below.
185+
Assert.Inconclusive("Skipped on WSL — broker silent auth is disabled there by design.");
186+
}
187+
182188
// Arrange: create two distinct app mocks (Loose so other providers in the iterator don't fail)
183189
var nonBrokerApp = new Mock<IPublicClientApplication>();
184190
var brokerApp = new Mock<IPublicClientApplication>();
@@ -207,6 +213,43 @@ public async Task MsalTokenProviders_SilentProvider_UsesBrokerApp_WhenProvided()
207213
nonBrokerApp.Verify(x => x.GetAccountsAsync(), Times.Never);
208214
}
209215

216+
[TestMethod]
217+
public async Task MsalTokenProviders_SilentProvider_UsesNonBrokerApp_OnWSL()
218+
{
219+
if (!PlatformInformation.IsWSL())
220+
{
221+
Assert.Inconclusive("Skipped on non-WSL — this test validates WSL-specific broker bypass behavior.");
222+
}
223+
224+
// Arrange: on WSL the silent provider should use the non-broker app even when a broker app is provided,
225+
// because the Linux broker daemon does not exist in WSL.
226+
// See: https://github.com/microsoft/artifacts-credprovider/issues/TODO
227+
var nonBrokerApp = new Mock<IPublicClientApplication>();
228+
var brokerApp = new Mock<IPublicClientApplication>();
229+
230+
nonBrokerApp.Setup(x => x.GetAccountsAsync())
231+
.ReturnsAsync(Array.Empty<IAccount>());
232+
nonBrokerApp.Setup(x => x.Authority)
233+
.Returns("https://login.microsoftonline.com/common");
234+
var nonBrokerAppConfig = new Mock<IAppConfig>();
235+
nonBrokerAppConfig.Setup(x => x.IsBrokerEnabled).Returns(false);
236+
nonBrokerApp.Setup(x => x.AppConfig).Returns(nonBrokerAppConfig.Object);
237+
238+
// broker app should NOT be called on WSL
239+
brokerApp.Setup(x => x.GetAccountsAsync())
240+
.ReturnsAsync(Array.Empty<IAccount>());
241+
242+
var providers = MsalTokenProviders.Get(nonBrokerApp.Object, loggerMock.Object, appInteractiveBroker: brokerApp.Object).ToList();
243+
var silentProvider = providers.First(p => p.Name == "MSAL Silent");
244+
245+
// Act
246+
await silentProvider.GetTokenAsync(new TokenRequest());
247+
248+
// Assert: non-broker app was used on WSL, broker app was not called
249+
nonBrokerApp.Verify(x => x.GetAccountsAsync(), Times.Once);
250+
brokerApp.Verify(x => x.GetAccountsAsync(), Times.Never);
251+
}
252+
210253
[TestMethod]
211254
public async Task MsalTokenProviders_SilentProvider_UsesNonBrokerApp_WhenNoBrokerProvided()
212255
{

src/Authentication/MsalTokenProviders.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ public static IEnumerable<ITokenProvider> Get(IPublicClientApplication app, ILog
1515
yield return new MsalManagedIdentityTokenProvider(app, logger);
1616

1717
// TODO: Would be more useful if MsalSilentTokenProvider enumerated over each account from the outside
18-
// Use the broker app for silent auth when available so WAM cache can be queried
19-
yield return new MsalSilentTokenProvider(appInteractiveBroker ?? app, logger);
18+
19+
// Use the broker app for silent auth on Windows and macOS so the broker cache can be queried.
20+
// WSL reports as Linux but has no broker daemon, so fall back to the non-broker app there.
21+
// See: https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/issues/5979
22+
yield return new MsalSilentTokenProvider(PlatformInformation.IsWSL() ? app : appInteractiveBroker ?? app, logger);
2023

2124
if (WindowsIntegratedAuth.IsSupported())
2225
{

src/Authentication/PlatformInformation.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,14 @@ public static string GetClrDescription()
7979
{
8080
return RuntimeInformation.FrameworkDescription;
8181
}
82+
83+
/// <summary>
84+
/// Returns true when running inside Windows Subsystem for Linux (WSL).
85+
/// WSL always sets the WSL_DISTRO_NAME environment variable.
86+
/// </summary>
87+
public static bool IsWSL()
88+
{
89+
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
90+
&& !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("WSL_DISTRO_NAME"));
91+
}
8292
}

0 commit comments

Comments
 (0)