Friday, July 25, 2014

Get Password from WPF PasswordBox with MVVM in a secure and simple way

Keeping cleartext passwords in memory is a security risk. Therefore the Password and SecurePassword property of WPF PasswordBox is not a DependencyProperty and cannot used for binding. To access the password in the ViewModel in a secure way some work have to be done.

At first we define an interface that contains just the SecureString Password as property.
public interface IHavePassword
{
    System.Security.SecureString Password { get; }
}

The View implements the IHavePassword interface. The Property Password in code-behind returns the SecurePassword of the PasswordBox.
public partial class LoginView : UserControlIHavePassword
{
    public LoginView()
    {
        InitializeComponent();
        DataContext = new LoginViewModel();
    }
 
    public System.Security.SecureString Password
    {
        get
        {
            return UserPassword.SecurePassword;
        }
    }
}

In the XAML part of the View the click event of the login button is send by using the RelayCommand pattern that builds on WPF Commanding. Therefore the Command and the CommandParameter properties are set. The View is set to the CommandParameter.
<UserControl x:Class="MvvmPassword.LoginView"
             x:Name="This"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        ...
        <PasswordBox x:Name="UserPassword"
                     Grid.Row="2"
                     Grid.Column="1"
                     Margin="4" />
        
        <Button x:Name="Login"
                Grid.Row="3"
                Grid.ColumnSpan="2"
                Margin="4"
                Content="Login"
                Command="{Binding LoginCommand}"
                CommandParameter="{Binding ElementName=This}"/>
        ...
    </Grid>
</UserControl>
In the ViewModel the LoginCommand is linked to the Login method. This method gets the View as parameter. The view is casted to defined interface IHavePassword. From that we can easily obtain the secure password.
private void Login(object parameter)
{
    var passwordContainer = parameter as IHavePassword;
    if (passwordContainer != null)
    {
        var secureString = passwordContainer.Password;
        PasswordInVM = ConvertToUnsecureString(secureString);
    }
}
The SecureString needs to be converted to string to validate the entered password. There are some pitfalls of converting a SecureString. A nice explanation of them can be found in How to properly convert SecureString to String by Fabio Pintos.
private string ConvertToUnsecureString(SecureString securePassword)
{
   if (securePassword == null)
   {
     return string.Empty;
   }
 
   IntPtr unmanagedString = IntPtr.Zero;
   try
   {
     unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
     return Marshal.PtrToStringUni(unmanagedString);
   }
   finally
   {
     Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
   }
}

The source code can be downloaded from https://code.msdn.microsoft.com/Get-Password-from-df012a86?redir=0

8 comments:

  1. Hmm it looks like yoour blog atte my first comment (it was super long) so
    I guess I'll just sum it up what I wrote and say, I'm thoroughly enjoying your blog.
    I too am an aspiriung blog writer buut I'm still new to everything.
    Do you have any tips and hints for beginner blog writers?I'd really
    appreciate it.

    ReplyDelete
  2. Please attach the full code link.

    ReplyDelete
  3. I don't understand completely. You say "In the ViewModel the LoginCommand is linked to the Login method." How does this link take place? If LoginCommand is a property within the ViewModel how can it receive a parameter?

    ReplyDelete
  4. This comment has been removed by the author.

    ReplyDelete
  5. This comment has been removed by the author.

    ReplyDelete
  6. Answered my own question using a delegate

    Something like
    public ICommand LoginCommand { get; private set; }

    Then within the constructor
    LoginCommand = new DelegateCommand < object > (Login);

    ReplyDelete
  7. You are welcome!

    For other readers, the question was: How does this link from LoginCommand to Login method take place?

    The full code can be found here: https://code.msdn.microsoft.com/Get-Password-from-df012a86?redir=0

    ReplyDelete