[Universal App] Usando las APIs Credential Locker

Login-01Introducción

En determinadas ocasiones, nuestras aplicaciones requieren seguridad o personalización por usuario. En estos casos son típicos problemas como, 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. Ahora con la llegada de las APIs Credential Locker disponibles en Windows.Security.Credentials, todo el proceso es mucho más simple.

En este artículo vamos a conocer las APIs de Credential Locker utilizñandolas en un ejemplo real donde veremos como almacenar, recuperar y eliminar claves.

¿Te apuntas?

¿Credential Locker?

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.

Primeros pasos

Comenzamos creando un nuevo proyecto:

Nueva Aplicación Universal

Nueva Aplicación Universal

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.

Comenzamos definiendo la interfaz de usuario:

<StackPanel Margin="12">
     <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">
          <Button Content="Guardar" />
          <Button Content="Recuperar" Margin="12, 0" />
          <Button Content="Borrar" />
     </StackPanel>
</StackPanel>

Muy simple. 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 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">
          <Button Content="Guardar" Command="{Binding SaveCommand}" />
          <Button Content="Recuperar" Margin="12, 0" Command="{Binding ReadCommand}" />
          <Button Content="Borrar" Command="{Binding DeleteCommand}" />
     </StackPanel>
     <ScrollViewer>
          <TextBlock Text="{Binding Info}"/>
     </ScrollViewer>
</StackPanel>

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

Interfaz del ejemplo

Interfaz del ejemplo

Continuamos centrándonos en la parte importante, la gestión de credenciales.

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);
}

Analicemos el código superior. 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))
     {
          return;
     }

     try
     {
          _passwordVaultService.Save(Source, User, Password);
          Info += string.Format("Datos guardatos. Resource: {0}, User: {1}, Password: {2}",
          Source, User, Password)
     }
     catch(Exception ex)
     {
          Info += ex.Message;
     }
}
Guardando credenciales

Guardando credenciales

Sencillo, verificamos que los datos que definen el credencial son válidos y en caso afirmativo utilizamos el método Save de nuestro servicio PasswordVaultService. Para recuperar un credencial:

public void ReadCommandDelegate()
{
     if (string.IsNullOrEmpty(Source) || string.IsNullOrEmpty(User))
     {
          Info += "La fuente y el usuario son obligatorios.";
          return;
     }

     try
     {
          var cred = _passwordVaultService.Read(Source, User);
          Info += string.Format("Datos obtenidos con éxito. Resource: {0}, User: {1}, Password: {2}",
          cred.Resource, cred.UserName, cred.Password);
     }
     catch (Exception ex)
     {
          Info += ex.Message;
     }
}
Recuperar un credencial

Recuperar un credencial

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 += "La fuente y el usuario son obligatorios.";
           return;
     }

     try
     {
          _passwordVaultService.Delete(Source, User);
          Info += string.Format("Datos eliminados con éxito. Resource: {0}, User: {1}, Password: {2}",
          Source, User, Password);
     }
     catch (Exception ex)
     {
          Info += ex.Message;
     }
}

Utilizamos el método Delete del servicio.

Eliminar un credencial

Eliminar un credencial

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

Buenas prácticas

  • 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.
  • Debemos controlar el ciclo de almacenamiento de credenciales en el Password Vault correctamente. No almacenar información hasta haber sido autenticado correctamente y haber marcado el usuario que desea recordar la información.

Conclusiones

En aplicaciones universales, es decir, tanto en aplicaciones Windows Phone como en aplicaciones Windows Store, contamos con una API, disponible bajo el namespace Windows.Security.Credentials 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.

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