Problem
I’ve run across an issue with binding to a PasswordBox. It appears to be a security issue, but because I’m utilising the MVVM paradigm, I’d like to avoid it. I came across some intriguing code here (has anyone tried it or something similar?)
http://www.wpftutorial.net/PasswordBox.html
It seems wonderful on paper, however I’m not sure how to get the password.
In my LoginViewModel, I have attributes for Username and Password. Because it’s a TextBox, Username is fine and functional.
I entered this using the above-mentioned code.
<PasswordBox ff:PasswordHelper.Attach="True"
ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>
The attribute in my LoginViewModel was updated when I had the PasswordBox as a TextBox with Binding Path=Password.
My code is straightforward; I simply have a Command for my Button. CanLogin is called when I press it, and if it returns true, Login is called. As you can see, I’ve checked my Username property, which works perfectly.
In Login, I transmit a Username and Password to my service; the Username has data from my View, but the Password is Null|Empty.
private DelegateCommand loginCommand;
public string Username { get; set; }
public string Password { get; set; }
public ICommand LoginCommand
{
get
{
if (loginCommand == null)
{
loginCommand = new DelegateCommand(
Login, CanLogin );
}
return loginCommand;
}
}
private bool CanLogin()
{
return !string.IsNullOrEmpty(Username);
}
private void Login()
{
bool result = securityService.IsValidLogin(Username, Password);
if (result) { }
else { }
}
This is what I’m up to.
<TextBox Text="{Binding Path=Username, UpdateSourceTrigger=PropertyChanged}"
MinWidth="180" />
<PasswordBox ff:PasswordHelper.Attach="True"
ff:PasswordHelper.Password="{Binding Path=Password}" Width="130"/>
I have my TextBox, this is no problem, but in my ViewModel the Password is empty.
Is there something I’m missing or am I doing something incorrectly?
I set a breakpoint, and sure enough, the code enters the static helper class, but my Password in my ViewModel is never updated.
Asked by mark smith
Solution #1
Maybe I’m missing something, but most of these methods seem to overcomplicate things and ignore secure practices.
This solution adheres to the MVVM design while also providing total security. Although it is technically code behind, it is really a “special case” binding. The ViewModel still doesn’t know anything about the View implementation, which it should if you’re trying to pass the PasswordBox into the ViewModel, in my opinion.
Automatic MVVM violation!= Code Behind. What you do with it is entirely up to you. We’re just manually coding a binding in this scenario, thus it’s all deemed part of the UI implementation and hence acceptable.
Just a simple property in the ViewModel. It’s “write only” because there shouldn’t be any reason to get it from outside the ViewModel, but it doesn’t have to be. It’s worth noting that it’s a SecureString rather than just a string.
public SecureString SecurePassword { private get; set; }
You create a PasswordChanged event handler in the xaml.
<PasswordBox PasswordChanged="PasswordBox_PasswordChanged"/>
Behind the scenes code:
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((dynamic)this.DataContext).SecurePassword = ((PasswordBox)sender).SecurePassword; }
}
Using this method, your password is always stored in a SecureString, ensuring utmost security. You can use the Password property instead if you don’t care about security or if you need the clear text password for a downstream method that requires it (note: most.NET methods that require a password also support a SecureString option, so you might not need a clear text password even if you think you do). As an example:
(ViewModel property)
public string Password { private get; set; }
(Code behind)
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((dynamic)this.DataContext).Password = ((PasswordBox)sender).Password; }
}
You could replace the (dynamic) cast with the interface of your ViewModel if you wanted to keep things strongly typed. But, as “regular” data bindings aren’t strongly typed either, it’s not a major issue.
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (this.DataContext != null)
{ ((IMyViewModel)this.DataContext).Password = ((PasswordBox)sender).Password; }
}
So you get the best of both worlds: your password is safe, your ViewModel has a property just like any other property, and your View is self-contained and doesn’t require any external references.
Answered by Steve In CO
Solution #2
My 2 cents:
Using WPF and MVVM, I once created a standard login dialog (user and password boxes, plus a “Ok” button). The password binding problem was handled by simply sending the PasswordBox control as a parameter to the command associated with the “Ok” button. So, in my opinion:
<PasswordBox Name="txtPassword" VerticalAlignment="Top" Width="120" />
<Button Content="Ok" Command="{Binding Path=OkCommand}"
CommandParameter="{Binding ElementName=txtPassword}"/>
The associated command’s Execute function was as follows in the ViewModel:
void Execute(object parameter)
{
var passwordBox = parameter as PasswordBox;
var password = passwordBox.Password;
//Now go ahead and check the user name and password
}
Although this partly breaks the MVVM pattern because the ViewModel now knows information about how the View is implemented, I could afford it in that particular case. I hope it is also useful to someone.
Answered by Konamiman
Solution #3
I’m sorry, but you’re doing it incorrectly.
The following security guideline should be tattooed on the inside of people’s eyelids: Passwords in plain text should never be memorized.
The absence of a DP for the Password property in the WPF/Silverlight PasswordBox is due to security concerns. If WPF/Silverlight kept a DP for Password, the framework would have to maintain the password itself in memory unencrypted. This is seen as a potentially dangerous security attack vector. The PasswordBox uses encrypted memory (of sorts), and the CLR property is the only way to get at the password.
When using the PasswordBox.Password CLR property, I recommend not putting it in any variables or using it as a value for any property. It’s a security no-no to keep your password in plain text on the client machine’s RAM. Get rid of that public string Password get; set; that you have up there.
Simply get the password out of PasswordBox.Password and send it to the server as soon as possible. Keep the password’s value out of sight and treat it like you would any other client machine text. Clear text passwords should not be kept in memory.
You should never bind to PasswordBox, even though it violates the MVVM pattern. Password Store your password in the ViewModel, or any other similar antics, as seen in the attached DP.
Here’s one if you’re seeking for a solution that’s been over-architected: 1. Make an IHavePassword interface with a single method that returns the password in plain text. 2. Add an IHavePassword interface to your UserControl. 3. Add the UserControl instance to your IoC as an IHavePassword interface implementer. 4. When a server request for your password occurs, contact your IoC for the IHavePassword implementation, and then acquire the coveted password.
It’s just my opinion.
— Justin
Answered by JustinAngel
Solution #4
This XAML can be used:
<PasswordBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=PasswordBox}}" CommandParameter="{Binding ElementName=PasswordBox}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</PasswordBox>
This command’s execution approach is as follows:
private void ExecutePasswordChangedCommand(PasswordBox obj)
{
if (obj != null)
Password = obj.Password;
}
This requires adding the System.Windows.Interactivity assembly to your project and referencing it with xmlns:i=”clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity;assembly=System.Windows.Interactivity;assembly=System.Windows.Interactivity;assembly=System.Windows.Interactivity;assembly=System.Windows.Interactivity;assembly=
Answered by Sergey
Solution #5
I spent a lot of time researching other options. Decorators were a no-go for me, behaviors messed up the validation UI, and code behind… really?
The best one yet is to stick to a custom attached property and bind to your SecureString property in your view model. As long as you can, keep it in there. Whenever you’ll need quick access to the plain password, temporarily convert it to an unsecure string using the code below:
namespace Namespace.Extensions
{
using System;
using System.Runtime.InteropServices;
using System.Security;
/// <summary>
/// Provides unsafe temporary operations on secured strings.
/// </summary>
[SuppressUnmanagedCodeSecurity]
public static class SecureStringExtensions
{
/// <summary>
/// Converts a secured string to an unsecured string.
/// </summary>
public static string ToUnsecuredString(this SecureString secureString)
{
// copy&paste from the internal System.Net.UnsafeNclNativeMethods
IntPtr bstrPtr = IntPtr.Zero;
if (secureString != null)
{
if (secureString.Length != 0)
{
try
{
bstrPtr = Marshal.SecureStringToBSTR(secureString);
return Marshal.PtrToStringBSTR(bstrPtr);
}
finally
{
if (bstrPtr != IntPtr.Zero)
Marshal.ZeroFreeBSTR(bstrPtr);
}
}
}
return string.Empty;
}
/// <summary>
/// Copies the existing instance of a secure string into the destination, clearing the destination beforehand.
/// </summary>
public static void CopyInto(this SecureString source, SecureString destination)
{
destination.Clear();
foreach (var chr in source.ToUnsecuredString())
{
destination.AppendChar(chr);
}
}
/// <summary>
/// Converts an unsecured string to a secured string.
/// </summary>
public static SecureString ToSecuredString(this string plainString)
{
if (string.IsNullOrEmpty(plainString))
{
return new SecureString();
}
SecureString secure = new SecureString();
foreach (char c in plainString)
{
secure.AppendChar(c);
}
return secure;
}
}
}
Avoid using a static event handler for the PasswordChanged event on the PasswordBox to ensure that the GC can collect your UI element. I also identified an issue where the control didn’t update the UI when the SecurePassword property was used to set it up, which is why I’m copying the password into Password instead.
namespace Namespace.Controls
{
using System.Security;
using System.Windows;
using System.Windows.Controls;
using Namespace.Extensions;
/// <summary>
/// Creates a bindable attached property for the <see cref="PasswordBox.SecurePassword"/> property.
/// </summary>
public static class PasswordBoxHelper
{
// an attached behavior won't work due to view model validation not picking up the right control to adorn
public static readonly DependencyProperty SecurePasswordBindingProperty = DependencyProperty.RegisterAttached(
"SecurePassword",
typeof(SecureString),
typeof(PasswordBoxHelper),
new FrameworkPropertyMetadata(new SecureString(),FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, AttachedPropertyValueChanged)
);
private static readonly DependencyProperty _passwordBindingMarshallerProperty = DependencyProperty.RegisterAttached(
"PasswordBindingMarshaller",
typeof(PasswordBindingMarshaller),
typeof(PasswordBoxHelper),
new PropertyMetadata()
);
public static void SetSecurePassword(PasswordBox element, SecureString secureString)
{
element.SetValue(SecurePasswordBindingProperty, secureString);
}
public static SecureString GetSecurePassword(PasswordBox element)
{
return element.GetValue(SecurePasswordBindingProperty) as SecureString;
}
private static void AttachedPropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// we'll need to hook up to one of the element's events
// in order to allow the GC to collect the control, we'll wrap the event handler inside an object living in an attached property
// don't be tempted to use the Unloaded event as that will be fired even when the control is still alive and well (e.g. switching tabs in a tab control)
var passwordBox = (PasswordBox)d;
var bindingMarshaller = passwordBox.GetValue(_passwordBindingMarshallerProperty) as PasswordBindingMarshaller;
if (bindingMarshaller == null)
{
bindingMarshaller = new PasswordBindingMarshaller(passwordBox);
passwordBox.SetValue(_passwordBindingMarshallerProperty, bindingMarshaller);
}
bindingMarshaller.UpdatePasswordBox(e.NewValue as SecureString);
}
/// <summary>
/// Encapsulated event logic
/// </summary>
private class PasswordBindingMarshaller
{
private readonly PasswordBox _passwordBox;
private bool _isMarshalling;
public PasswordBindingMarshaller(PasswordBox passwordBox)
{
_passwordBox = passwordBox;
_passwordBox.PasswordChanged += this.PasswordBoxPasswordChanged;
}
public void UpdatePasswordBox(SecureString newPassword)
{
if (_isMarshalling)
{
return;
}
_isMarshalling = true;
try
{
// setting up the SecuredPassword won't trigger a visual update so we'll have to use the Password property
_passwordBox.Password = newPassword.ToUnsecuredString();
// you may try the statement below, however the benefits are minimal security wise (you still have to extract the unsecured password for copying)
//newPassword.CopyInto(_passwordBox.SecurePassword);
}
finally
{
_isMarshalling = false;
}
}
private void PasswordBoxPasswordChanged(object sender, RoutedEventArgs e)
{
// copy the password into the attached property
if (_isMarshalling)
{
return;
}
_isMarshalling = true;
try
{
SetSecurePassword(_passwordBox, _passwordBox.SecurePassword.Copy());
}
finally
{
_isMarshalling = false;
}
}
}
}
}
And here’s how XAML is used:
<PasswordBox controls:PasswordBoxHelper.SecurePassword="{Binding LogonPassword, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}">
In the view model, my property looked like this:
[RequiredSecureString]
public SecureString LogonPassword
{
get
{
return _logonPassword;
}
set
{
_logonPassword = value;
NotifyPropertyChanged(nameof(LogonPassword));
}
}
The RequiredSecureString is a simple custom validator that works like this:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
public class RequiredSecureStringAttribute:ValidationAttribute
{
public RequiredSecureStringAttribute()
:base("Field is required")
{
}
public override bool IsValid(object value)
{
return (value as SecureString)?.Length > 0;
}
}
You’ve got it now. A fully functional and thoroughly tested pure MVVM solution.
Answered by MoonStom
Post is based on https://stackoverflow.com/questions/1483892/how-to-bind-to-a-passwordbox-in-mvvm