microsoft-authentication-library-for-dotnet: [Bug] WAM interactive dialog (the Account Picker) is immediately canceled when shown in an elevated app

Which Version of MSAL are you using ? MSAL 4.29.0

Platform .NET 5

What authentication flow has the issue? Desktop / Mobile: Interactive

Is this a new or existing app? This is a new app or experiment

Repro C# console app, .NET 5, target framework net5-windows10.0.17763.0.

static async Task Main()
{
    IPublicClientApplication app = PublicClientApplicationBuilder
        .Create("my-client-id")
        .WithAuthority("https://login.microsoftonline.com/my-tenant-id")
        .WithExperimentalFeatures()
        .WithBroker()
        .Build();

    await app.AcquireTokenInteractive(new string[] { "my-resource-id/.default" })
        .ExecuteAsync();
}

Expected behavior The WAM interactive dialog (account picker) should be shown.

Actual behavior If the console app is run elevated, the WAM dialog briefly flashes and is immediately canceled (MSAL returns authentication_canceled). If the console app is run non-elevated, the WAM dialog is shown as expected.

Additional context/ Logs / Screenshots I see this issue on .NET framework, .NET Core 3.1, and .NET 5.

In case this is a bug in WAM itself, I am reproing this on Win10 20H2.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 15 (6 by maintainers)

Commits related to this issue

Most upvoted comments

One possible interesting solution may be to set the COM security settings on the specific proxy/interface for the WAM account control, rather than try and change the COM security settings for the entire process via the registry or CoInitializeSecurity.

Another common scenario in which you might set process-wide security programmatically is when you would like to set default security for the entire process but you have one or more objects within that process that expose interfaces with special security requirements. In this case, you can call CoInitializeSecurity to set security for the process, allowing COM to handle most of the security checks, and you can call other methods to set security for the objects with special security needs. Calling these methods and functions is described in Setting Security at the Interface Proxy Level.

Source: https://docs.microsoft.com/en-us/windows/win32/com/setting-processwide-security-with-coinitializesecurity

Sometimes the client needs fine-grained control over the security on calls to particular interfaces. For example, security might be set at a low level for the process but calls to a particular interface might require a higher authentication level, such as encryption. The methods of the IClientSecurity interface allow the client to change the security settings associated with calls to a particular interface by controlling the security settings at the interface-proxy level. […] SetBlanket is commonly used to raise the authentication level for a particular interface proxy to a higher level of security protection. However, in some situations, it might also be helpful to lower the authentication level for a particular interface proxy. For instance, suppose the default authentication level for the process is some value other than RPC_C_AUTHN_LEVEL_NONE and the client and server are in separate domains that do not trust each other. In this case, calls to the server will fail unless the client calls SetBlanket to lower the authentication level to RPC_C_AUTHN_LEVEL_NONE.

Source: https://docs.microsoft.com/en-us/windows/win32/com/setting-security-at-the-interface-proxy-level

This sounds like what’s happening, no?

“For instance, suppose the default authentication level for the process is some value other than RPC_C_AUTHN_LEVEL_NONE and the client and server are in separate domains that do not trust each other.”

Not sure if you’ve explored this possibility? @bgavrilMS @pmaytak

@maheshdevaraju 4.56.0 uses a new WAM broker implementation that works with elevated privileges. So it’s a different issue from this original one. Please create a separate issue with repro steps, details, and verbose logs and we’ll look into it.

The root cause, as I understand it, is that MSAL makes a COM call to AccountsSettigsPane and sets a callback. When the user is done clicking around in the AccountsSettingsPane control, it needs to get back to MSAL via that callback. It looks like calling an elevated process from a COM component is contrary to the security settings of COM.

A workaround has been provided by the Windows team:

This is one of the native APIs that is historically known to have problems calling from .Net. The issue is that this needs to be called before COM remoting is initialized in a process or it will happen implicitly, and there are things CLR may do early in the process lifetime that cause this. This is mentioned (with some details inaccurate) on the pinvoke.net page: You shouldn’t call CoInitializeSecurity from managed code. http://pinvoke.net/default.aspx/ole32/CoInitializeSecurity.html

Most of what you can do with CoInitializeSecurity, including access permissions as needed here, can also be done with an AppID key for the exe (see here and here). Note that for COM to read this from an elevated process it must be in HKLM.

New issue has been created. #4360

I’m using WAM broker(MSAL.NET 4.56.0) in a VSTO Excel Add-in application based on .NET Framework 4.8.

The app works without any issues when it is not elevated, but when the App is elevated I face the “authentication_canceled” error code.

  IPublicClientApplication app = PublicClientApplicationBuilder
      .Create("CLIENT-ID")
      .WithDefaultRedirectUri()
      .WithBroker(new BrokerOptions(BrokerOptions.OperatingSystems.Windows))
      .Build();

  await app.AcquireTokenInteractive(scopes)
                      .WithParentActivityOrWindow(hWnd)
                      .ExecuteAsync()

Based upon the comments above I tried to use WindowsNativeUtils.InitializeProcessSecurity, but looks like this is deprecated. Is there any other way I can fix this issue?

@lacomc We are currently moving to a new better WAM experience (currently in preview), and the wiki was updated for that. The current (soon-to-be-legacy) WAM experience is documented here. Unfortunately this workaround doesn’t all the time - sometimes the security is set before the app code runs, which results in an error.

I suggest trying the new WAM which works fine in elevated processes. This describes how to implement.

Also I see that you’re in a Visual Studio team? CC’ing @gladjohn who has been collaborating with the VS team on testing the preview WAM package.

Starting in next MSAL version (4.32), the error will be a bit more descriptive when app process is elevated and WAM returns no accounts. If the app must be run in admin mode, in short-term the recommendation is to call a helper method, WindowsNativeUtils.InitializeProcessSecurity. Described a bit more in Using WAM in an elevated process wiki.

Yep, seems like CoInitializeSecurity is the appropriate workaround for now. And setting the security for an interface proxy, unfortunately, doesn’t affect the callee process calling back into the elevated caller process. Short-term we’ll probably just make the error message in MSAL.NET more descriptive, until a fix exists.