How to validate PasswordBox WPF

18,298

Solution 1

Try setting ValidatesOnDataErrors=True and ValidatesOnExceptions=True on your binding:

<PasswordBox ...
   local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password,
      UpdateSourceTrigger=Explicit, 
      ValidatesOnDataErrors=True, 
      ValidatesOnExceptions=True}"
/>

Solution 2

Set Mode=TwoWay on your binding

local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password,Mode=TwoWay,
UpdateSourceTrigger=Explicit}"

Solution 3

Another solution, without using any "unsecure" string in the middle, is to adapt the Window code, something like this:

Let's suppose I have an MVVM object like this, with WPF validation using IDataErrorInfo:

public class MyObject : INotifyPropertyChanged, IDataErrorInfo
{
    ...
    public SecureString SecurePassword
    {
        get
        { ... }
        set
        {
            ...
            OnPropertyChanged("SecurePassword");
        }
    }

    ...

    string IDataErrorInfo.Error { get { return Validate(null); } }
    string IDataErrorInfo.this[string columnName] { get { return Validate(columnName); } }

    private string Validate(string memberName)
    {
        string error = null;
        ...
        if (memberName == "SecurePassword" || memberName == null)
        {
            // this is where I code my custom business rule
            if (SecurePassword == null || SecurePassword.Length == 0)
            {
                error = "Password must be specified.";
            }
        }
        ...
        return error;
    }

}

And a Window Xaml with a PasswordBox like this:

<PasswordBox Name="MyPassword" PasswordChanged="MyPassword_Changed" ... />

Then, the corresponding Window code like this will trigger PasswordBox binding:

// add a custom DependencyProperty
public static readonly DependencyProperty SecurePasswordProperty =
    DependencyProperty.RegisterAttached("SecurePassword", typeof(SecureString), typeof(MyWindow));

public MyWindow()
{
    InitializeComponent();

    DataContext = myObject; // created somewhere

    // create a binding by code
    Binding passwordBinding = new Binding(SecurePasswordProperty.Name);
    passwordBinding.Source = myObject;
    passwordBinding.ValidatesOnDataErrors = true;
    // you can configure other binding stuff here
    MyPassword.SetBinding(SecurePasswordProperty, passwordBinding);
}

private void MyPassword_Changed(object sender, RoutedEventArgs e)
{
    // this should trigger binding and therefore validation
    ((MyObject)DataContext).SecurePassword = MyPassword.SecurePassword;
}

Solution 4

As far as I remember, the only way to add validation on a PasswordBox is to throw a new ValidationException in the setter of the binding property for SecurePassword. The PasswordBoxAssistant will not help you with this.

Share:
18,298

Related videos on Youtube

Sonhja
Author by

Sonhja

Partially programmer, partially designer! An WPF lover, Android developer and .Net contributor! Learning more and more everyday :) And happy to help others work!

Updated on September 15, 2022

Comments

  • Sonhja
    Sonhja over 1 year

    I'm trying to make a validation for a PasswordBox. For making validations I followed this link, that shows how to validate on TextBox.

    The problem comes with PasswordBoxes. Because its Password is not bindable due to security reasons, I tried to make a binding following this link (also explained here, for CodeProject users).

    So, apparently, fantastic! I can bind my PasswordBox with its Password property, so then I can bind with my validation. But it ignores me...

    This is a regular TextBox that I use and works fine:

    <local:ErrorProvider Grid.Column="1" Grid.Row="2" >
        <TextBox Width="160" 
              HorizontalAlignment="Left" 
               Name="textBoxUserPass" 
               Text="{Binding Path=Password, UpdateSourceTrigger=Explicit}" />
     </local:ErrorProvider>
    

    And this is the PasswordBox I tried to simulate:

    <local:ErrorProvider Grid.Column="1" Grid.Row="2" >
          <PasswordBox Width="160"
              HorizontalAlignment="Left"
              Name="textBoxUserPass"
              local:PasswordBoxAssistant.BindPassword="True"
              local:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, UpdateSourceTrigger=Explicit}" />
     </local:ErrorProvider>
    

    This is how I get the BindingExpression for each TextBox:

    BindingExpression beUserName = textBoxUserName.GetBindingExpression(TextBox.TextProperty);
    if (beUserName != null) beUserName.UpdateSource();
    

    And this is how I get it for the PasswordBox:

    BindingExpression bePassword = textBoxUserPass.GetBindingExpression(PasswordBoxAssistant.BoundPassword);
    if (bePassword != null) bePassword.UpdateSource();
    

    If we made any mistake (defined on my Validation class), when I do this:

    if (!beUserName.HasError && !bePassword.HasError)
    

    each BindingExpression should say true of false depending on error validations. But for my PasswordBox never gets the value... Any idea?

  • Sonhja
    Sonhja about 11 years
    Hummm can you provide an example or link? It sounds as a solution.
  • Cristian Chereches
    Cristian Chereches about 11 years
    This is what I found in an old app that I was working on:public SecureString NewPassword { get { return _newPassword; } set { _newPassword = value; string error = IsPasswordValid(); if (!string.IsNullOrEmpty(error)) { throw new ValidationException(error); } } }
  • Sonhja
    Sonhja about 11 years
    Hummm, gonna try it, but the exact solution is the one Richard Deeming posted (for this case). But I'm gonna try this one too, as I have this particular case also at my code.
  • Daniel
    Daniel over 5 years
    I do hope people realize the PasswordBox is itself insecure, since it will happily decrypt the password for any application that asks nicely. Just attach to the process, and via reflection, say, "Hey PasswordBox, what's in the Password property?" I get that you can get a little protection from memory scraping, specifically, by avoiding storing it in a string field, but for most use cases, it's already game over if any malicious payload has been installed--and perhaps not really worth fretting over.
  • Simon Mourier
    Simon Mourier over 5 years
    @Daniel - SecureString's does not protect from a live debugger or similar live threats. A good explanation of handled threats is here: blogs.msdn.microsoft.com/shawnfa/2004/05/27/… (also make sure you read comments from Shawn)