-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CredUIPromptForWindowsCredentials crashes in unpackaged app #4340
Comments
There is a working WinForms project included which does not use WinUI or WASDK. |
I guess the other projects work too on your system using Win11? |
Yes. |
Thinking about it for a little, have you tried referencing the Windows App SDK in a WinForms or WPF application and seeing if you have the same problem? |
I did check with |
What do you mean by referencing? Addin a |
I mean simply adding the NuGet package to a project and setting WindowsPackageType to None and maybe setting the Windows App SDK self contained setting too. |
I tried your suggestion, even getting <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.20348.0</TargetFramework>
<TargetPlatformMinVersion>10.0.19044.0</TargetPlatformMinVersion>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<WindowsPackageType>None</WindowsPackageType>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
<UseRidGraph>true</UseRidGraph>
<Platforms>x64</Platforms>
<RuntimeIdentifiers>win10-x64</RuntimeIdentifiers>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.240404000" />
</ItemGroup>
</Project> public Form1()
{
InitializeComponent();
try
{
Microsoft.UI.Xaml.Window window = new Microsoft.UI.Xaml.Window();
}
catch (Exception)
{
}
CredentialService credentialService = new CredentialService();
credentialService.PromptForCurrentCredentials(this.Handle, "Credentials", "Please enter");
} "Unfortunately" this does not crash on my machine. |
Hi @Balkoth using Windows.Security.Credentials.UI;
using Windows.Security.Credentials;
namespace WinUICommunity;
public static class CredentialHelper
{
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool GetComputerName(StringBuilder lpBuffer, ref uint nSize);
private static async Task<CredentialPickerResults> PickCredentialBase(string caption, string message, CredentialSaveOption credentialSaveOption, AuthenticationProtocol authenticationProtocol, bool alwaysDisplayDialog)
{
uint nSize = 260;
StringBuilder sbComputerName = new StringBuilder((int)nSize);
GetComputerName(sbComputerName, ref nSize);
var options = new CredentialPickerOptions()
{
TargetName = sbComputerName.ToString(),
Caption = caption,
Message = message,
CredentialSaveOption = credentialSaveOption,
AuthenticationProtocol = authenticationProtocol,
AlwaysDisplayDialog = alwaysDisplayDialog
};
return await CredentialPicker.PickAsync(options);
}
public static async Task<CredentialPickerResults> PickCredential(string caption, string message, CredentialSaveOption credentialSaveOption, AuthenticationProtocol authenticationProtocol, bool alwaysDisplayDialog)
{
return await PickCredentialBase(caption, message, credentialSaveOption, authenticationProtocol, alwaysDisplayDialog);
}
public static async Task<CredentialPickerResults> PickCredential(string caption, string message, CredentialSaveOption credentialSaveOption, AuthenticationProtocol authenticationProtocol)
{
return await PickCredentialBase(caption, message, credentialSaveOption, authenticationProtocol, true);
}
public static async Task<CredentialPickerResults> PickCredential(string caption, string message, CredentialSaveOption credentialSaveOption)
{
return await PickCredentialBase(caption, message, credentialSaveOption, AuthenticationProtocol.Basic, true);
}
public static async Task<CredentialPickerResults> PickCredential(string caption, string message)
{
return await PickCredentialBase(caption, message, CredentialSaveOption.Selected, AuthenticationProtocol.Basic, true);
}
public static PasswordCredential GetPasswordCredential(string resource, string username)
{
if (string.IsNullOrEmpty(resource) || string.IsNullOrEmpty(username))
{
return null;
}
try
{
var vault = new PasswordVault();
return vault.Retrieve(resource, username);
}
catch (Exception)
{
}
return null;
}
public static void AddPasswordCredential(string resource, string username, string password)
{
if (string.IsNullOrEmpty(resource) || string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
return;
}
var vault = new PasswordVault();
var credential = new PasswordCredential(resource, username, password);
vault.Add(credential);
}
public static void RemovePasswordCredential(string resource, string username)
{
if (string.IsNullOrEmpty(resource) || string.IsNullOrEmpty(username))
{
return;
}
var vault = new PasswordVault();
var credential = vault.Retrieve(resource, username);
vault.Remove(credential);
}
public static async Task<bool> RequestWindowsPIN(string message)
{
// Check if Windows Hello is available
if (await UserConsentVerifier.CheckAvailabilityAsync() != UserConsentVerifierAvailability.Available)
{
return false;
}
var consentResult = await UserConsentVerifier.RequestVerificationAsync(message);
if (consentResult == UserConsentVerificationResult.Verified)
{
// Windows Hello PIN was successfully verified
return true;
}
else
{
// Verification failed or was canceled
return false;
}
}
} |
Thanks but your sample has the one big problem why i have to use PInvoke: Your sample uses string for the password and therefore the password is in cleartext in memory until the app gets shutdown. So i would prefer if someone from the team can check this on win10. |
Yes, this is unfortunate. You ruled out it being a platform invoke problem because it should be crashing in the packaged WinUI 3 application and the WPF/WinForms application if it was a platform invoke issue. This unfortunate result actually provides the same logic for the Xaml runtime and the Windows App Runtime. If it was the Xaml runtime, then the packaged application version should be crashing, if it was the bootstrapper or registration free WinRT functionality then the WPF/WinForms application should be crashing. One easy way to get a definitive answer would be to make an unpackaged C++ WinUI application and directly call this function or, to try to mimic the call portion of platform invoke, use runtime dynamic linking to call it (aka, LoadLibrary/GetProcAddress). |
On my Windows 10 OS (22H2), it works for me with maxversiontested in the Manifest file, otherwise I get "Invalid pointer"
|
Starts working when i put |
Is anyone from the team looking into this or does the maxversiontested hack confirm this is a non-issue from WASDK? |
This is incredibly frustrating, because this problem is affecting software in production. |
Why does no one on the team care for this issue? What is missing here, that is holding you back, to investigate and acknowledge or deny that this is a WASDK issue? |
Can you share either the output-log dump of @ghost1372 - the |
FWIW, I put together a little WPF app using the private async void Clickery_Click(object sender, RoutedEventArgs e)
{
// Show a credential picker to acquire the user's domain credentials.
var credPicker = new CredentialPickerOptions
{
Message = "Sign in",
Caption = "Windows Credential Picker",
TargetName = "Windows Authentication",
AuthenticationProtocol = AuthenticationProtocol.Negotiate,
CredentialSaveOption = CredentialSaveOption.Hidden,
CallerSavesCredential = false,
};
var credResult = await CredentialPicker.PickAsync(credPicker);
Clickery.Content = credResult.ErrorCode == 0 ? "Success" : "Failure";
} ... which ran and showed the Windows Hello prompt to get me to sign in. The resulting I'll try with an unpackaged WASDK WinUI3 app, but my hunch is it'll work there as well. I've asked some folks internally to see if there's known problems with this Win32 API. |
@Balkoth - I'm able to use the Windows credential picker API from WPF, WinUI3, unpackaged apps. See https://github.com/jonwis/jonwis.github.io/tree/user/jonwis/credpicker/code/CredPickerSampleWinUI3/CredPickerSampleWinUI3 for the details. Can you try it out and see? That'd let you avoid all the hand-rolled p/invoke and just use our WinRT API call support. The one drawback is that while CredUIPrompt... lets you specify an HWND as the parent for the prompt, the CredentialPicker does not; for Win32 apps the UX gets parented to the desktop. I've filed http://task.ms/50726835 for the team to add a |
This... |
Just to ask, in what way is the credential in clear text in memory until the application shuts down? |
Because the password is retrieved in a string object and strings live forever. |
I would be extremely surprised if that is true. |
If i remember correctly the runtime itself decides whether to intern strings and therefore keep them forever. Either way, using string for the password is a non deterministic approach on if and when cofidential data gets unloaded from memory. |
FWIW, the .NET folks have this statement on SecureString - https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md - specifically, that it provides minimal actual value, and should not be used in new designs. I've asked the Windows Security team to chime in on this thread for a definitive statement. See also https://devblogs.microsoft.com/oldnewthing/20130529-00/?p=4223 ... note that the point of However, under the covers, it turns out that Strictly speaking, however, this violates the HSTRING contract which is that - like .NET String types - they are immutable. Someone with this code (in C++/WinRT) would be very sad: winrt::hstring pw = (co_await CredentialPicker::PickAsync(...)).CredentialPassword();
UsePasswordToAuth(pw); // pw.data() is now non-null but points to all zeroes. While in C# the ABI output of Re the GC and string lifetime and zeroing - correct, the GC allocates memory for the String from whatever store it has. If that's the OS heap, blocks are only zero'd when they're handed out, not on a call to |
The supplemental documentation for String.Intern paints a different picture. The runtime only automatically interns strings created from string literals, your code has to explicitly call Intern otherwise. |
Describe the bug
Please see the attached solution, there are three projects, one packaged WASDK, one unpackaged WASDK and one WinForms project. All three projects use the same
CredentialService
file/class to display the credential ui. The unpackaged app crashes here:Steps to reproduce the bug
Expected behavior
I would expect that either all projects crash, because there may be something wrong with my PInvoke code, or none. But as both packaged and WinForms project run without problems, i suspect there is something wrong with the unpackaged nature of the project.
Screenshots
No response
NuGet package version
Windows App SDK 1.5.2: 1.5.240404000
Packaging type
Unpackaged
Windows version
Windows 10 version 22H2 (19045, 2022 Update)
IDE
Visual Studio 2022
Additional context
I don't know what version of WASDK introduced this problem, because at some point in time this code was developed and working with WASD (1.2.221116.1).
The text was updated successfully, but these errors were encountered: