[Windows 10] Password Vault

LockIntroducció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." + "\r\n";
          return;
      }

      try
      {
          _passwordVaultService.Save(Source, User, Password);
          Info += string.Format("Credentials saved. Resource: {0}, User: {1}, Password: {2}",
                  Source, User, Password) + "\r\n";
      }
      catch(Exception ex)
      {
          Info += ex.Message + "\r\n";
      }
}
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." + "\r\n";
          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) + "\r\n";
      }
      catch (Exception ex)
      {
         Info += ex.Message + "\r\n";
      }
}
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." + "\r\n";
          return;
      }

      try
      {
          _passwordVaultService.Delete(Source, User);
          Info += string.Format("Data successfully removed. Resource: {0}, User: {1}, Password: {2}",
                  Source, User, Password) + "\r\n";
      }
      catch (Exception ex)
      {
          Info += ex.Message + "\r\n";
      }
}
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 GitHubRecordar 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

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s