Conceptos Básicos de seguridad en .NET (parte I)

La seguridad es un tema que debe estar presente desde el comienzo del diseño de todo sistema de información, más aún si este sistema será utilizado por usuarios desde Internet.
Dos conceptos básicos para entender la seguridad de los sistemas es la autenticación y la autorización.

Autenticación

La autenticación es el proceso mediante el cual el sistema identifica y válida que el usuario pruebe quién dice ser, es similar a cuando hacemos una visita a un edificio y un guardia de seguridad en la entrada nos solicita una credencial para que nos identifiquemos, el mecanismo de credenciales más usadas en los sistemas de información es el login y el password.
Entonces en definición la autenticación es el mecanismo que se refiere a probar y validar quiénes somos dentro del sistema, esta identidad consiste generalmente del login de usuario y del rol asociado con ese login, NET proporciona los siguientes mecanismos de autenticación:

Windows Authentication Utiliza la seguridad del sistema operativo windows y compara las credenciales (login y password) con las credenciales de Windows una vez identificado, windows utiliza un número de 96 bits llamado SID (security identifier) para identificarlo.

Passport Authentication En este tipo los usuarios utilizan sus cuentas de Hotmail o de Windows Messenger para autenticarse y por ende su servicio de registro en caso de no tener una cuenta passport, para utilizar esta autenticación es necesario descargar e instalar Passport SDK desde Microsoft Passport Network.

Forms Authentication (ASP.NET) Aquí se realiza mediante un formulario solicitando el login y el password al usuario, cuando ASP.NET válida las credenciales como correctas crea una cookie encriptada que se adjunta a cada respuesta de petición, por eso se dice que esta autenticación es basada en token (token-based), si el runtime de ASP .NET no encuentra la cookie entonces redirige al usuario a la pantalla del login, este tipo de autenticación es la más personalizable y portable que las anteriores.

Estos mecanismos se utilizan en conjunto con la seguridad basada en roles de .NET (role-based security) que se fundamenta en dos conceptos importantes: identidades y principales.
La identidad de un usuario está representada en .NET por los siguientes tipos de identidades que se encuentran representadas en el Framework por clases que implementan la interfaz IIdentity.

Windows identity Se basa en los métodos de autenticación soportados por el sistema operativo Windows, esta identidad tiene la propiedad de hacerse pasar por otro usuario con la característica de impersonation(suplantación) además de ser una forma muy segura de autenticar usuarios.

Generic identity Se basa en un método personalizado de autenticación que se define a nivel aplicación, al ser un método personalizado por
lo tanto no depende de las características del sistema de seguridad de Windows.

Passport identity Utiliza la autenticación del modulo de Passport de Microsoft donde los usuarios utilizan las credenciales de Hotmail o Windows Live para acceder a cualquier sistema que implemente el servicio Passport (single sign-inservice).

Si bien se recomienda utilizar los mecanismos proporcionados por el framework, .NET permite también crear mecanismos personalizados de autenticación implementando la interfaz IIdentity.

Código del programa ejemplo
WindowsIdentitySample con la clase WindowsIdentity:

Al ejecutarse el programa mostrará la siguiente salida en Microsoft Windows:


Y la siguiente salida al ejecutarse en Linux utilizando Mono

A continuación el código de ejemplo del programa
GenericIdentitySample utilizando la clase GenericIdentity:

Al ejecutarse el programa mostrará la siguiente salida en Microsoft Windows:



Y la siguiente salida al ejecutarse en Linux utilizando Mono

 Descarga el código fuente del ejemplo

Trabajando LINQ para XML con Monodevelop Parte II de II

Esta es la segunda parte del post anterior Trabajando LINQ para XML con Monodevelop, aunque este tutorial supone que los dos proyectos están dentro la misma solución, los dos proyectos son independientes uno del otro, por lo que pueden crearse en diferentes soluciones.

Consultando XML con LINQ

Ahora agregamos un segundo proyecto a nuestra solución, este proyecto será una aplicación GTK# que llamaremos “SegundoLinqXML” como se muestra en la siguiente imagen y que nos mostrará como consultar el archivo XML con LINQ creado con la aplicación de consola anterior.



Utilizando el diseñador agregamos y acomodamos los siguientes controles GTK# con sus respectivos identificadores al formulario.

Tipo de control:Gtk.Entry NombretxtQuery

Tipo de control:Gtk.Button NombreBtnBuscar

Tipo de control:Gtk.RadioButton NombresRbCodigo,rbIdArticulo,rbNombre

Tipo de control:Gtk.TreeView NombresResultados

Colocando los controles el formulario deberá verse como en la siguiente imagen

El código completo es el siguiente:

El siguiente fragmento de código muestra como realizar la consulta del archivo XML donde la variable col adquiere el valor de cualquier elemento dentro del elemento table y donde el valor contenga el texto escrito dentro de txtQuery, es aquí donde en esencia se utilizan las expresiones de consulta de LINQ una vez que se carga el documento XML en memoria.

Construimos la aplicación pulsando el botón F8, seleccionamos el archivo de proyecto y haciendo click con e botón secundario del ratón seleccionamos la aplicación para que se inicie al ejecutar la solución, al ejecutarla teclear un valor y pulsar el botón consultar observaremos cualquiera de los siguientes resultados dependiendo del control radio seleccionado.




 Descarga el código fuente

Trabajando LINQ para XML con Monodevelop Parte I de II

XML se ha convertido en un excelente estándar abierto para el intercambio de información entre aplicaciones de software debido a la manera de representar información estructurada, independiente de la plataforma, lenguaje de programación o sistema operativo, es utilizado extensamente en archivos y protocolos de Internet por ser un formato fácil de leer y suficientemente flexible para adaptarse a muchos propósitos. Debido a estas características XML y sus tecnologías están completamente integradas y soportadas por la plataforma .NET mediante un conjunto de clases que proporcionan lectura y escritura de documentos, validación, navegación, serialización, transformación y búsquedas. Aunque estas clases son suficientes para trabajar con XML su utilización no es sencilla y puede producir código difícil de mantener, por lo que .NET incorpora LINQ para XML (LINQ to XML) como una mejor manera de trabajar con XML.

Creando el archivo XML

Para mostrar de una manera práctica la utilización de LINQ para XML, ejecutamos MonoDevelop y creamos una nueva solución en el menú “Archivo”, del lado derecho de la ventana de nueva solución seleccionamos el icono que dice “Solución en blanco” y en el cuadro de texto nombre escogemos “LinqXML”, esta será la solución que contenga los dos proyectos de este tutorial.


Agregamos a nuestra solución un proyecto de consola, le llamamos CrearXML , como se muestra en la siguiente imagen.


Para que el soporte de LINQ a XML es importante hacer referencia a los siguientes ensamblados:

System.Linq Es el ensamblado principal y básico que contiene todas las clases e interfaces para trabajar con LINQ.

System.Xml.LinqContiene las clases y extensiones para manipular XML con LINQ.

Esto se logra haciendo click derecho sobre el archivo de proyecto y en el menú desplegable escogemos la opción “Editar referencias” (Edit References) como se muestra en la imagen siguiente.


Ahora completamos el código generado por monodevelop, para que el programa completo quede como en el siguiente listado.

La diferencia de la sintaxis para crear documentos XML con respecto a la sintaxis empleada con las clases del ensamblado System.Xml, es que esta sintaxis se enfoca más en los elementos (representados por la clase XElement) que en el documento (representado en la clase Xdocument ).
En este listado creamos el documento XML de una manera declarativa anidando varias objetos XElement dentro de un objeto Xdocument , al final llamamos al método Save para guardar el XML en el disco.
Construimos la aplicación pulsando la tecla F8 y al ejecutarse veremos el resultado en la ventana de salida de MonoDevelop como se muestra en la imagen siguiente.

 Descarga el código fuente

El patrón singleton con Monodevelop y PostgreSQL

En el post anterior mostré un ejemplo utilizando el patrón Singleton con conexiones a bases de datos SQL Server ejecutándonse bajo Microsoft Windows, ahora mostraré las modificaciones que tuve que realizar a ese ejemplo para que funcione con
PostgreSQL como base de datos y Linux como sistema operativo.
Primeramente abrí el proyecto en Monodevelop, después descargue la última versión de la biblioteca Npgsql para tener actualizado los últimos cambios de esta biblioteca, lo cuál es recomendable ya que además de arreglar los errores el equipo responsable agrega nuevas funcionalidades, una vez descargada la biblioteca comence con las siguientes modificaciones:

1-.Quitar la referencia al ensamblado de Sql Server (System.Data.SqlClient) y reemplazarlo por el de PostgreSQL (Npgsql), esto se hace dentro del explorador de la solución, haciendo click derecho sobre las referencias como se muestra en la imagen.

Nos aparecerá la ventana “edit references”, ahí escogemos la pestaña que dice “Ensamblado .Net” para buscar en el sistema de archivos en la ruta donde descargamos y descomprimimos la biblioteca Npgsql,esto para seleccionar el ensamblado Npgsql.dll como se muestra en la siguiente imagen.

2-. Reemplazar en el código de las clases DataBase y DataBase2 respectivamente el namespace System.Data.SqlClient por Npgsql
using System.Data.SqlClient;
por
using Npgsql;

3-. También en el código de esas clases reemplazar las líneas donde se hace la declaración del objeto que representa la conexión y donde se realiza la creación de dicho objeto, reemplazar las siguientes líneas:

SqlConnection _conn = null;
_conn = new SqlConnection();

por

NpgsqlConnection _conn = null;
_conn = new NpgsqlConnection();

4-. En estas mismas clases cambiar el tipo de excepción en el catch del try del metódo GetConnection().
catch(SqlException x)
por
catch(NpgsqlException x)

5-. Reemplazar el evento StateChange del objeto NpgsqlConnection y el delegado asociado al evento, por una propiedad de tipo string
que infome de las características de la conexión, esto debido a que aún el proveedor de datos de postgreSQL no cuenta con esta característica.

StateChange += delegate(object o,StateChangeEventArgs args){
Info = String.Format(" {1}| {2}| {3}|",args.CurrentState.ToString(),
System.DateTime.Now.ToLocalTime(), _conn.DataSource,_conn.Database);

por

Info = String.Format(" {0}|{1}| {2}| {3}|",GetCurrentState,System.DateTime.Now.ToLocalTime(),
_conn.DataSource ,_conn.Database);

Agregando la siguiente propiedad

public string GetCurrentState{ get {return (IsOpen == true ? "Open" : "Closed");}}

Terminando los cambios debemos de configurar MonoDevelop para que al ejecutar la aplicación el programa se ejecute en una terminal propia y no en la ventana de salida (output) de MonoDevelop, esto se hace en el menú principal en la opción “Proyecto” eligiendo el submenú “Opciones”, nos mostrará una pantalla como la siguiente imagen.


Después de estos cambios podemos observar el resultado, de forma idéntica al resultado logrado en la plataforma Microsoft.
Ingreso de los parámetros de conexión


Sin el uso del patrón Singleton, cambian los tiempos en la conexión


Usando el patrón Singleton, el tiempo es único.

 Descarga el código fuente

El patrón singleton

Muchos problemas de rendimiento (performance) y de escalabilidad (scalability) ocurren si no manejamos correctamente las conexiones a las bases de datos, hay que tener en presente que las conexiones para acceder a una base de datos son un recurso que consume memoria y tiempo de procesador, por lo que solo se deben crear las conexiones necesarias para el funcionamiento de las aplicaciones y estas deben cerrarse tan pronto hayan sido ocupadas.
Una buena práctica es que todas las clases que acceden a los recursos de la base de datos utilicen siempre una única conexión sin importar el número de instancias que estas clases generen al ser ejecutadas dentro de una aplicación, una solución recomendada a este escenario es utilizar los patrones de diseño de software.

Conectarse a una base de datos con el patrón Singleton

Es un patrón de diseño del tipo creacional que nos asegura la creación de únicamente la instancia de un objeto sin importar el número de veces que se intenten crear más instancias de ese objeto.
citando el clásico libro de the gang of four Design Patterns:Elements of Reusable Object-Oriented Software, 1995, Pearson Addison Wesley “The Singleton design pattern must ensure a class only has one instance, and provide a global point of access to it”

Este patrón se utiliza para representar un objeto de hardware (por ejemplo una impresora), un componente del sistema operativo (un archivo o un directorio) o bien un recurso externo limitado (como una conexión a una base de datos), esta instancia revisará si ya ha sido creada, atenderá las peticiones de los objetos que la utilicen como un punto global de acceso (similar a una variable global) y sera responsable del mantener el seguimiento de su estado.
El esqueleto clásico de un Singleton es el siguiente:

A continuación voy a mostrar el ejemplo de una clase que representa una conexión a una base de datos sin utilizar el patrón Singleton, para mostrar como se crea una conexión por cada ocasión que nosotros llamamos a la clase lo cual repercute en la escalabilidad y el desempeño de la aplicación si se tuvieran que invocar decenas o cientos las ejecuciones a esta clase.



A continuación el programa principal:


using System;
using System.Collections.Generic;
using System.Linq;

namespace PostSingleton
{
public class Program
{
static List _conns = null;
public static int Main(string[] args)
{
_conns = new List();
string op = null;
Console.ForegroundColor = ConsoleColor.White;
do{
Console.Write("\n");
Console.WriteLine("+-------------------------------+");
Console.WriteLine(" Ejemplo del patron singleton para conexiones");
Console.Write("\n");
Console.WriteLine("a) Conexión DB");
Console.WriteLine("b) Ver Conexiones");
Console.WriteLine("q) Salir");
Console.Write("\n");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("Elija su opción y pulse : ");
Console.ForegroundColor = ConsoleColor.White;
op = Console.ReadLine().ToLower();
switch(op){
case "a":
ConectarDB();
break;
case "b":
VerConexiones();
break;
}
}while(op != "q");
Console.WriteLine("\nHasta luego");
return 0;

}
static void VerConexiones(){
try{
Console.Clear();
Console.WriteLine("\nListado de conexiones");
Console.Write("\n");
Console.WriteLine("+------------------------------------+");
Console.WriteLine("| CONEXIONES ACTIVAS |");
Console.WriteLine("+------------------------------------+\n");
if(_conns.Count > 0){
var q = from c in _conns where c.IsOpen == true select c;
foreach(var i in q){
Console.WriteLine("{0}",i.Info);
}}else Console.WriteLine("NO HAY CONEXIONES ACTIVAS");
}catch(Exception x){ Console.WriteLine("Excepcion " + x.Message); }
}
static void ConectarDB(){
try{
Console.Clear();
Console.WriteLine("Datos de la cadena de conexion ");
Console.ForegroundColor = ConsoleColor.Yellow;
Console.Write("Servidor y pulse : ");
string server = @Console.ReadLine();
Console.Write("Base de datos y pulse : ");
string database = @Console.ReadLine();
Console.Write("Usuario y pulse : ");
string user = @Console.ReadLine();
Console.Write("Password y pulse : ");
string password = @Console.ReadLine();
Console.ForegroundColor = ConsoleColor.White;
string connStr = String.Format(
"Data Source={0};Initial Catalog={1};User ID={2};Password={3};",
server,database,user,password);
Console.WriteLine("Intentando conexión...");
DataBase db = new DataBase(connStr);
_conns.Add(db);
VerConexiones();
}catch(Exception x){
Console.WriteLine("Excepción " + x.Message);
}
}
static void Exit(){
Environment.Exit(0);
}}}



Al compilar y ejecutar la aplicación se mostrará el siguiente menú.

Escogiendo la opción (a) nos mostrará el menú para solicitarnos los parámetros de la cadena de conexión, si repetimos este procedimiento nos mostrará
las conexiones hechas hacia el servidor, una por cada vez que hayamos completado la opción (a) como se muestra en la siguiente imagen.

Observamos en la imagen como es diferente el tiempo entre cada una de las conexiones ya que se crea una conexión por cada llamado.

Bien ahora mostraremos el mismo ejercicio utilizando el patrón Singleton en el código de la clase DataBase, pero para no sobrescribir la clase DataBase del ejercicio anterior, nombraremos la clase Singleton como DataBase2.



Analizamos la clase y vemos el uso de los modificadores private y static en el constructor hace que no se pueda crear la clase de forma directa, sino solo a traves del método public GetInstance(string conStr) que regresa la instancia creada y por ende sus propiedades y métodos públicos.
Antes de ejecutar el programa principal para que utilice la clase con el singleton, hay que modificar la líneas donde se crea la lista de conexiones


static List _conns = null;
_conns = new List();

y tambien donde se invoca la conexión con la base de datos.


_conns.Add(DataBase2.GetInstance(connStr));

Haciendo estos cambios, ejecutando la aplicación, seleccionando la opción (a) para conectarse a una base de datos y creando varias conexiones debemos de ver
la salida del programa como en la siguiente pantalla:

Observamos en la imagen como el tiempo entre cada una de las conexiones es siempre el mismo, ya que se crea una sola instancia global de acceso.

 Descarga el código fuente

Uso de funciones PL/SQL en postgreSQL

Una función (function) en PostgreSQL son sentencias SQL agrupadas y precompiladas para ejecutarse en bloque dentro del servidor, a diferencia de las consultas SQL donde cada consulta es procesada en tiempo de ejecución por el servidor , las funciones procedurales son compilados cuando son creados, ya que el servidor asume que serán ejecutados más de una vez, un función ofrece las siguientes ventajas:

  • No sobrecarga la comunicación cliente/servidor al evitar enviar una consulta tras otra, en su lugar procesa una consulta tras otra y envía únicamente el resultado.
  • Cuando y se ejecuta la primera vez se crea un plan preparado de ejecución, las siguientes ejecuciones reutilizan el plan preparado.
  • Agrega estructuras de control y capacidad de calculo al lenguaje SQL.
  • Las mismas consultas están disponibles para varias aplicaciones.
  • Seguridad los datos solo están accesibles mediante las funciones y evita el uso de SQL injection.

De los lenguajes más utilizados para crear funciones en postgreSQL, se encuentra PL/pgSQL, el cual se distribuye como un módulo cargable junto con postgreSQL, para emplearlo en nuestra base de datos es necesario darlo de alta, de la siguiente manera.

Fig 1 Agregando el soporte PL/SQL

Revisamos si ya lo tenemos disponible en nuestra base de datos para utilizarlo
La sintaxis de PL/pgSQL (similar al lenguaje PL/SQL de Oracle)

Fig 2 Comprobando la instalación del lenguaje PL/SQL

Utilizando PL/pgSQL con C#

En este ejemplo usaremos PL/pgSQL y C# para resolver un requerimiento practico como seria relacionar la columna city de nuestra tabla authors en nuestra base de datos con una tabla llamada cities donde se encontrará la información de la columna ciudad mas un identificador.

Fig 3 La tabla autores

La relación deberá de quedar de la siguiente manera, donde la columna city se debe cambiar por la clave primaria de la tabla cities que tendrá como clave primaria la clave de la ciudad y una columna adicional llamada city que contendrá el nombre de la ciudad.

Ahora usamos la siguiente función AddCities(varchar) para tomar los valores de la columna city en la tabla authors, crear un identificador único para la llave primaria, insertar ese valor de clave primaria junto con el nombre de la ciudad y por último sustituir los valores en la columna city y reemplazarlos con el valor de la llave primaria en la tabla cities.

using System;
using Gtk;
using System.Text;
using System.Data;
using Npgsql;
using NpgsqlTypes;

namespace PgForm {
class PgForm : Window {
Label lbMsg = new Label("DEBUG: ");
Entry txtNameFunction = new Entry();
Entry txtArg = new Entry();

public PgForm() : base("Ejecutar funciones"){
BorderWidth = 8;
SetDefaultSize(208,220);
this.DeleteEvent += new DeleteEventHandler(OnWindowDelete);
Frame frame = new Frame ("Ejecutar funciones");
Add (frame);
VBox MainPanel = new VBox (false, 8);
MainPanel.BorderWidth = 8;
frame.Add (MainPanel);
MainPanel.PackStart(new Label("Nombre de la funcion"),false,false,0);
MainPanel.PackStart(txtNameFunction,false,false,0);
MainPanel.PackStart(new Label("Si recibe un argumento de tipo varchar")
                    ,false,false,0);
MainPanel.PackStart(txtArg,false,false,0);
Button btnSubmit = new Button("Ejecutar funcion");
btnSubmit.Clicked += new EventHandler(btnSubmitClicked);
MainPanel.PackStart(btnSubmit,false,false,0);
MainPanel.PackStart(lbMsg,false,false,0);
lbMsg.LineWrap = true;
ShowAll();
}

public void OnWindowDelete(object o, DeleteEventArgs args) {
Application.Quit(); 
}

void btnSubmitClicked(object o, EventArgs args){
string cStr = "Server=127.0.0.1;Port=5432;User Id=postgres;" + 
 "Password=postgres;Database=pubs;";
try{
using(NpgsqlConnection conn = new NpgsqlConnection(cStr))
{
conn.Open();
NpgsqlCommand cmd = new NpgsqlCommand(txtNameFunction.Text, conn);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
//en caso de tener un parametro como en nuestra funcion de ejemplo
if(txtArg.Text.Length > 0){
cmd.Parameters.Add(new NpgsqlParameter());
cmd.Parameters[0].NpgsqlDbType = NpgsqlDbType.Varchar;
cmd.Parameters[0].Value = txtArg.Text;
}
lbMsg.Text += cmd.ExecuteScalar().ToString();
}}catch(Exception e){
lbMsg.Text += e.Message;
}
}

static void Main(string[] args) {
Application.Init();
new PgForm();
Application.Run();
}}  
}

Lo compilamos y lo ejecutamos

    mcs /t:winexe -r:System.Data,Npgsql -pkg:gtk-sharp-2.0 ExecutePgFunction.cs
Fig 5 Compilación del programa

Podemos probar nuestro programa invocando la funcion version() predeterminada de PostgreSQL.

Fig 6 Ejecutando la función version() de PostgreSQL

Al ejecutar la función sin argumentos desde el formulario se vera el mismo resultado.

Fig 7 El programa ejecutando función version().

Aquí el driver de PostgreSQL para .NET ejecuta la función usando la clase NpgsqlCommand la cual recibe como argumento el nombre de la función y la conexión al servidor donde se encuentra.

    NpgsqlCommand cmd = new NpgsqlCommand(“version”, conn);

Si la función recibe parámetros, debemos de crear una instancia de la clase NpgsqlParameter() por cada uno de los parametros que reciba, es muy importante no olvidar indicarle a la clase NpgsqlCommand que el comando que ejecutaremos es un stored procedure o una función pl/sql, esto lo hacemos mediante la instrucción:

    cmd.CommandType = System.Data.CommandType.StoredProcedure;

Para mayor referencia no olvidar leer la documentación del data provider para PostgreSQL.
Si todo es ejecutado correctamente, ya podemos probar la función AddCities con el argumento del nombre de la ciudad y debe devolvernos la clave primaria de la tabla cities.

Fig 8 El programa ejecutando la función AddCities

 Descarga el código fuente en Plpgsql (Download Plpgsql source code)

 Descarga el código fuente en C# (Download C# source code)