[Windows 10] Password Vault

Introducción

En muchas de las Apps que desarrollamos contamos con opciones relacionadas con la seguridad
donde debemos afrontar problemas como almacenar usuario y contraseña,
encriptar la información, gestionar múltiples dispositivos, etc.

Era un proceso “habitual” pero que requiere tener en cuentas
bastantes aspectos.  En este artículo vamos a ver lo sencillo que lo
tenemos utilizando las APIs Credential Locker disponibles en Windows.Security.Credentials.

NOTA: Estas APIs ya las teníamos disponibles desde Windows 8.1.

El almacén de credenciales

El almacén de credenciales nos permite almacenar y administrar de forma segura
contraseñas de usuarios de una aplicación o servicio específico de modo
que por un lado, los datos almacenados de una aplicación se transfieren
automáticamente a los otros dispositivos de confianza del usuario,
simplificando el proceso de autenticación tanto a los usuarios como a
nosotros, y por otro lado, no es posible desde una aplicación o servicio
acceder a los credenciales asociados con otra aplicación o servicio.

Password Vault

Crearemos un nuevo proyecto UAP:

Nueva App UAP

Nueva App UAP

Añadimos las carpetas Views, ViewModels y Services además de las clases base necesarias para implementar el patrón MVVM de la misma forma que vimos en este artículo.

Nuestro objetivo sera muy sencillo. Nuestra aplicación de ejemplo
pedirá fuente, usuario y contraseña permitiéndo con tres sencillos
botones, añadir, recuperar y eliminar credenciales utilizando la API
Credential Locker.

Definiendo la interfaz de usuario

Comenzamos definiendo la interfaz de usuario:

<StackPanel Margin="12">
     <StackPanel
                Margin="0, 12">
                <TextBlock
                    Text="PasswordVault"
                    FontSize="32" />
     </StackPanel>
     <StackPanel Orientation="Vertical">
          <TextBox Header="Source"
                   PlaceholderText="https://facebook.com" />
          <TextBox Header="User"
                   PlaceholderText="user@mail.com" />
          <PasswordBox Header="Password"
                       PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal"
                 HorizontalAlignment="Center"
                 Margin="0, 12">
          <Button Content="Save" />
          <Button Content="Read" Margin="12, 0" />
          <Button Content="Delete" />
     </StackPanel>
     <ScrollViewer>
          <TextBlock />
     </ScrollViewer>
</StackPanel>

Permitimos obtener la información de seguridad requerida y contamos con tres botones de acción. En la viewmodel correspondiente contaremos con propiedades para obtener la información escrita en cada una de las cajas de texto:

// Variables
private string _source;
private string _user;
private string _password;
private string _info;
  
public string Source
{
     get { return _source; }
     set { _source = value; }
}
  
public string User
{
     get { return _user; }
     set { _user = value; }
}
  
public string Password
{
     get { return _password; }
     set { _password = value; }
}
  
public string Info
{
     get { return _info; }
     set
     {
          _info = value;
          RaisePropertyChanged("Info");
     }
}

Y cada botón, ejecutará un comando en la viewmodel:

// Commands
private ICommand _saveCommand;
private ICommand _readCommand;
private ICommand _deleteCommand;
  
public ICommand SaveCommand
{
     get { return _saveCommand = _saveCommand ?? new DelegateCommand(SaveCommandDelegate); }
}
  
public ICommand ReadCommand
{
     get { return _readCommand = _readCommand ?? new DelegateCommand(ReadCommandDelegate); }
}
  
public ICommand DeleteCommand
{
     get { return _deleteCommand = _deleteCommand ?? new DelegateCommand(DeleteCommandDelegate); }
}
  
public void SaveCommandDelegate()
{
  
}
  
public void ReadCommandDelegate()
{
  
}
  
public void DeleteCommandDelegate()
{
  
}

De modo que nuestra interfaz bindeada a las propiedades y comandos correspondientes quedara como podemos ver a continuación:

<StackPanel Margin="12">
     <StackPanel
                Margin="0, 12">
                <TextBlock
                    Text="PasswordVault"
                    FontSize="32" />
     </StackPanel>
     <StackPanel Orientation="Vertical">
          <TextBox Text="{Binding Source, Mode=TwoWay}"
                   Header="Source"
                   PlaceholderText="https://facebook.com" />
          <TextBox Text="{Binding User, Mode=TwoWay}"
                   Header="User"
                   PlaceholderText="user@mail.com" />
          <PasswordBox Password="{Binding Password, Mode=TwoWay}"
                       Header="Password"
                       PlaceholderText="1234abcd" />
     </StackPanel>
     <StackPanel Orientation="Horizontal"
                 HorizontalAlignment="Center"
                 Margin="0, 12">
          <Button Content="Save" Command="{Binding SaveCommand}" />
          <Button Content="Read" Margin="12, 0" Command="{Binding ReadCommand}" />
          <Button Content="Delete" Command="{Binding DeleteCommand}" />
     </StackPanel>
     <ScrollViewer>
          <TextBlock Text="{Binding Info}"/>
     </ScrollViewer>
</StackPanel>

Hasta aqui, la interfaz y estructura básica de nuestro ejemplo.

Nuestra interfaz

Nuestra interfaz

Gestión de credenciales

Para realizar la gestión de credenciales utilizaremos las APIs Credential Locker disponibles en Windows.Security.Credentials. Vamos a crear un servicio con la siguiente definición:

public interface IPasswordVaultService
{
     void Save(string resource, string userName, string password);
  
     PasswordCredential Read(string resource, string userName);
  
     IReadOnlyList<PasswordCredential> GetAll();
  
     void Delete(string resource, string userName);
}

NOTA: El servicio será inyectado por Ioc en nuestra viewmodel.

El servicio contará con cuatro métodos:

  • Save: Nos permitirá guardar credenciales.
  • Read: Nos permitirá recuperar un credencial concreto.
  • GetAll: Recupera todos los credenciales que tengamos almacenados en el Credential Locker.
  • Delete: Eliminará un credencial concreto almacenado previamente.

Nos centramos a continuación en la implementación de cada método. Comenzamos por el método Save:

public void Save(string resource, string userName, string password)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = new PasswordCredential(resource, userName, password);
     vault.Add(cred);
}

Primero, obtenemos una referencia al Credential Locker usando on objeto de tipo PasswordVault definido en el namespace Windows.Security.Credentials. Continuamos creando un objeto de tipo PasswordCredential
que representará el credencial a almacenar con la referencia a nuestra
Aplicación o el tipo de Login utilizado además de los credenciales en
si, usuario y contraseña. Añadiremos el credencial creado al almacén de
credenciales utilizando el método PasswordVault.Add.

Continuamos con el método Read:

public PasswordCredential Read(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
  
     return vault.Retrieve(resource, userName);
}

Contamos con una gran variedad de opciones para recuperar
credenciales del almacén. En el código de la parte superior utilizamos
la forma más simple posible. Contando con el nombre de la App o tipo de
Login además del nombre de usuario, podemos recuperar la información
utilizando el método PasswordVault.Retrieve.

En el método GetAll utilizamos el método PasswordVault.RetrieveAll  para recuperar todos los credenciales almacenados en la Aplicación:

public IReadOnlyList<PasswordCredential> GetAll()
{
     PasswordVault vault = new PasswordVault();
  
     return vault.RetrieveAll();
}

Además de las dos formas utilizadas contamos con otras opciones para recuperar credenciales:

Por último, nos centramos en el método Delete, que como podemos imaginar se encargará de eliminar un credencial en concreto:

public void Delete(string resource, string userName)
{
     PasswordVault vault = new PasswordVault();
     PasswordCredential cred = vault.Retrieve(resource, userName);
     vault.Remove(cred);
}

De nuevo, es un proceso muy sencillo que podemos hacer con pocas
líneas. Accedemos de nuevo al almacén de credenciales mediante un objeto
de tipo PasswordVault y utilizamos el método PasswordVault.Remove  para eliminar el credencial almacenado pasado como parámetro.

Con nuestro servicio para gestionar el almacén de credenciales
preparado, solo nos falta definir la acción de cada comando. Al guardar
el credencial:

public void SaveCommandDelegate()
{
      if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User) || string.IsNullOrEmpty(Password))
      {
          Info += "The Source, the User and the Password are required." + "rn";
          return;
      }
 
      try
      {
          _passwordVaultService.Save(Source, User, Password);
          Info += string.Format("Credentials saved. Resource: {0}, User: {1}, Password: {2}",
                  Source, User, Password) + "rn";
      }
      catch(Exception ex)
      {
          Info += ex.Message + "rn";
      }
}
Credencial guardado

Credencial guardado

Para recuperar un credencial:

public void ReadCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
     {
          Info += "The Source and the User are required." + "rn";
          return;
     }
 
     try
     {
          var cred = _passwordVaultService.Read(Source, User);
          Info += string.Format("Data recovered successfully. Resource: {0}, User: {1}, Password: {2}",
                  cred.Resource, cred.UserName, cred.Password) + "rn";
      }
      catch (Exception ex)
      {
         Info += ex.Message + "rn";
      }
}
Recuperando credenciales

Recuperando credenciales

Utilizaremos tras validar la información, el método Read de nuestro servicio. Y por último, en el comando para eliminar credenciales:

public void DeleteCommandDelegate()
{
      if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
      {
          Info += "The Source and the User are requiered." + "rn";
          return;
      }
 
      try
      {
          _passwordVaultService.Delete(Source, User);
          Info += string.Format("Data successfully removed. Resource: {0}, User: {1}, Password: {2}",
                  Source, User, Password) + "rn";
      }
      catch (Exception ex)
      {
          Info += ex.Message + "rn";
      }
}

Eliminando credenciales

Eliminando credenciales

Utilizamos el método Delete del servicio.

Podéis descargar el ejemplo completo realizado a continuación:

También tenéis el código fuente disponible e GitHub:

Ver GitHub

Recordar que podéis dejar en los comentarios cualquier tipo de sugerencia o pregunta.

Conclusiones

Bajo el namespace Windows.Security.Credentials contamos con una API llamada Credential Locker
que nos permite gestionar credenciales de usuario con suma facilidad.
La gran ventaja de utilizar la API es que nos almacena la información en
un almacén seguro, la información es encriptada al ser almacenada. Además, otra de las grandes ventajas de utilizar la API es el roaming de los credenciales entre dispositivos de confianza bajo la misma cuenta Microsoft.

A tener en cuenta

El almacén de credenciales esta pensado para facilitar la tarea de la
gestión de la seguridad en nuestras aplicaciones. No se recomienda su
uso para almacenar grandes cantidades de información. Contamos con otras
APIs válidas y más adecuadas para esta necesidad.

Más información

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *