Conversiones y curiosidades acerca de C#

En el libro Java Puzzlers: Traps, Pitfalls, and Corner Cases de Joshua Bloch y Neal Gafter publicado por Addison Wesley Professional en el año 2005 encontré ciertas curiosidades y trucos acerca de la programación en Java que me llamaron la atención, los autores explican la razón de tales escollos por lo que tome algunos ejemplos del libro para programarlos con C# y ver si obtendría los mismos resultados que sus contrapartes en Java.

Aquí algunos ejemplos del libro con las mismas preguntas, la diferencia únicamente es la implementación de Java a C#.

1-. En el siguiente programa ¿Es en todos los casos seguro que el método IsOdd determine correctamente si el número entero es par o no?

2-.¿Qué valor imprime el siguiente programa?

3-. ¿Cuál es el resultado del siguiente programa?

Analicemos cada uno de los ejemplos.

Ejemplo 1

Observaciones Al ejecutar el programa y pasarle un número entero como argumento desde la línea de comandos al parecer el programa determina si ese número es par o no, como en las siguientes imagen.

Pero el método que determina si el número es par o impar falla al pasarle un número negativo par o impar, esto siendo que toma como parámetro un entero y la mitad de los valores del tipo entero son negativos, el método supone que los residuos son únicamente positivos siendo que cuando la operación del residuo regresa un número que no es cero conserva el signo del dividendo.

La solución entonces es cambiar el método para que la comparación en vez de quedar igual a uno cambie a diferente a cero


static bool IsOdd(int i)
{
return i % 2 != 0;
}

La siguiente imagen nos muestra el resultado:

Ejemplo 2

Observaciones Este ejemplo se refiere a una mala práctica de programación, si examinamos el código puede que no nos percatemos que el último digito del segundo sumando en lugar de ser el número uno (1) es la letra l (ele) minúscula, por lo que una de las buenas prácticas de programación señaladas en el libro es no utilizar la letra l (ele) minúscula para indicar un valor numérico de tipo long o como variable.


Console.WriteLine(12345 + 5432l);

En todo caso el compilador de C# nos lanza la advertencia al compilar el programa,


Puzzle2.cs(9,34): warning CS0078: The 'l' suffix is easily
confused with the digit '1' (use 'L' for clarity)
Compilation succeeded - 1 warning(s)

que nos recomienda usar siempre la letra mayúscula para evitar confusiones, como se muestra en la siguiente imagen.

Ejemplo 3

Observaciones si examinamos el código del programa, al ejecutarlo debería de imprimir XX o sea dos veces el carácter ‘X’, un carácter por cada expresión por expresión, sin embargo al ejecutar el programa imprime 8888 como en la siguiente imagen:

Esto se debe a ciertas reglas del operador ternario u operador condicional (condicional operator) donde el primer operando debe ser de tipo bool que se cumple en el caso de ambas expresiones, la diferencia está en el segundo y tercer operador donde las reglas son:

  1. Si los dos operadores son del mismo tipo la expresión devuelve ese tipo.
  2. Si hay una conversión implícita del segundo al tercero pero no del tercero al segundo entonces la expresión devuelve el tipo del tercer operador.
  3. Si hay una conversión implícita del tercero al segundo pero no del segundo al tercero entonces la expresión devuelve el tipo del segundo operador.

En el ejemplo 3 en la primera expresión existe la conversión implícita de char a int por lo que valor de la expresión es de tipo int y a imprimir es de tipo carácter se cumple la primera regla y en la segunda expresión no existe conversión implícita de int a char por lo se cumple la tercera regla.

En ambos casos es el equivalente de


Console.Write((int)x);
Para eliminar la confusión cambiemos el código a una conversión explicita:


El resultado es el esperado como se muestra en la siguiente imagen:

  Descarga el código fuente

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

Autorización

La autorización ocurre inmediatamente después de la autenticación y es como el sistema determina que recursos pueden utilizarse de acuerdo con la autenticación, regresando a la analogía del edificio la autorización ocurre después que nos identificamos (autenticación) ante el guardia y le decimos a que piso vamos, entonces nos da un gafete con el número de piso y que nos autoriza movernos únicamente en ese piso mientras nos encontremos dentro el edificio.

La interfaz IPrincipal

El modelo de seguridad basado en roles (roled-based security o RBS) permite controlar el acceso de los usuarios a los recursos en base a su identidad y su pertenencia a un grupo o membership, este modelo esta diseñado para ser independiente de la plataforma donde se implemente por lo que .NET utiliza el concepto de principal (representado por la interfaz IPrincipal) como una forma de abstraer este modelo y encapsular la información acerca del contexto de seguridad (security context) de la entidad (usuario o objeto) que ejecuta el código.

Hay diferentes tipos de objetos Principal cada uno para cada tipo de identidad y de membership, .NET proporciona los siguientes tipos de principales.

  • Windows Principal: Si utilizamos la seguridad Integrada de Windows este objeto representa la identidad, la autenticación y los roles de Windows.
  • Generic Principal: Representa una seguridad a nivel aplicación, independiente de la seguridad de Windows, los roles y los usuarios utilizan un método personalizado de autenticación como por ejemplo una tabla en una base de datos.

Hay dos técnicas para crear objetos Principal dependiendo de si una aplicación requiere hacer la validación algunas veces o durante toda su ejecución. Vamos a mostrar estas formas utilizando como ejemplo el objeto WindowsPrincipal.

La primera técnica se recomienda si requerimos hacer la validación de cierto código algunas veces durante la ejecución, la sintaxis es:


WindowsIdentity wi = WindowsIdentity.GetCurrent();
WindowsPrincipal wp = new WindowsPrincipal(wi);

En esas lineas, primero obtenemos una instancia de WindowsIdentity al consultar la cuenta de Windows que ejecuta el código con el método GetCurrent y después la usamos como parámetro para construir un objeto WindowsPrincipal.

La segunda técnica se utiliza si requerimos hacer la validación durante toda la ejecución de la aplicación entonces en este caso debemos establecer la seguridad de Windows a nuestro hilo principal de ejecución ya que .NET de forma predeterminada no estable esa propiedad, entonces la sintaxis es la siguiente:


AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal wp = (WindowsPrincipal)Thread.CurrentPrincipal;

En esas líneas primeramente establecemos la política de autorización al dominio de la aplicación con el valor de la enumeración PrincipalPolicy , después obtenemos el Principal del hilo de ejecución y hacemos un casting a un objeto WindowsPrincipal, si no establecemos la política no podremos hacer el casting de Thread.CurrentPrincipal a WindowsPrincipal ya que como mencionamos anteriormente .NET no establece esta propiedad.

Una vez teniendo el objeto WindowsPrincipal además de las propiedades y métodos de la clase WindowsIdentity podemos determinar su pertenencia a un grupo o rol, con el método IsInRole.
El método IsInRole de WindowsPrincipal tiene tres sobrecargas la primera recibe como argumento una cadena conteniendo el nombre del grupo o rol que debe escribirse para grupos basados en dominios de la siguiente forma:

[NombreDelDominio]\[Grupo]

O de la siguiente forma si es para grupos de la computadora local.

[NombreDeLaMaquina]\[Grupo]

La segunda sobrecarga recibe un RID (Role Identifier) y la tercera recibe una enumeración WindowsBuiltInRole
La tabla siguiente lista los identificadores del rol con su correspondiente valor en la enumeración WindowsBuiltInRole


+----------------+------+
|AccountOperator |0x224 |
|Administrator |0x220 |
|BackupOperator |0x227 |
|Guest |0x222 |
|PowerUser |0x223 |
|PrintOperator |0x226 |
|Replicator |0x228 |
|SystemOperator |0x225 |
|User |0x221 |
+----------------+------+

El siguiente programa demuestra el uso de la primera técnica de validación para conocer la autorización de una entidad.

Al compilar y ejecutar el programa con una cuenta de administrador mostrará el siguiente resultado:



Ahora bien, si ejecutamos el programa con el comando

runas /user:[Usuario] [Programa]

en este caso con la cuenta del usuario postgres,como se muestra en la imagen:

El programa mostrará el siguiente resultado:

Y ahora demostramos la segunda técnica utilizando la política del dominio de la aplicación, algo más elaborado que el ejemplo anterior, lo ejemplificamos con el código de clase Roles.cs y la clase SimplePrincipalThread.cs que listamos a continuación.

El listado Roles.cs

El listado SimplePrincipalThread.cs


Al compilar las clases y ejecutar el programa con la opción false nos mostrará la excepción de que no hemos establecido una política de autorización.

Si ejecutamos el programa sin argumentos nos mostrará las instrucciones de uso.

Si ejecutamos el programa correctamente,nos mostrará la información como en la siguiente imagen

 Descarga el código fuente

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

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

Code Access Security CAS, la seguridad en el código

CAS (Code Access Security), es la forma en que los ensamblados solicitan permisos para acceder a ciertos recursos para su ejecución en el CLR, esto proporciona seguridad a nivel código,como una forma complementaria y adicional a la seguridad del sistema operativo.

Esta seguridad debe estar presente sobre todo si de desarrollan componentes, plugins, add-ons o juegos que serán ejecutados en diferentes ambientes que no conocemos ni controlamos.
Señalo que esta seguridad es complementaria y en ningún momento deberá reemplazar la seguridad del sistema operativo.
Para explicar voy a usar un ejemplo, un banco nos solicito realizar un aplicación donde el usuario genera unos archivos de estados de cuenta esta aplicación en un diseño inicial esta compuesta por un formulario y un ensamblado que se encarga de generar el estado de cuenta en un archivo XML.
Obviamente una aplicación de esta naturaleza, necesitaría una disciplina de análisis y diseño, pero para fines ilustrativos, logramos llegar a la etapa de construcción sin la utilización del CAS.

La aplicación se mostraría más o menos así,

La operación de la aplicación consiste que cuando el usuario presione el botón de generar, se generaría un archivo XML en una carpeta restringida para ciertos usuarios, el código del método del ensamblado es el siguiente:

El método de la aplicación para invocar el método del ensamblado es el siguiente:

La aplicación es utilizada sin ningún problema hasta que varios archivos de estados de cuenta no coinciden al utilizarlos en la contabilidad, se encuentran localizados en una ubicación que no es la ruta predeterminada y el sistema operativo no indica ninguna excepción en las bitácoras de seguridad.
Supongamos que un usuario autenticado construye un programa malintencionado que ejecuta el método de nuestro ensamblado para escribir los estados de cuenta afuera de la carpeta predeterminada un código como el siguiente:

Para compilar este código usamos:
csc /r:Ensamblado1.dll SinPermiso.cs

Con la opción /r le indicamos al compilador, que haga referencia al metadata del ensamblado indicado, en este caso al Ensamblado1 donde se encuentra el método para generar estados de cuenta.
Al revisar los códigos observamos que el método esta implementado para generar los archivos debajo de una carpeta llamada [Banks] en la partición [C:\\] y que la protección de los valores del ensamblado dependerá de las validaciones que implementemos en el formulario de la aplicación, mas no del ensamblado mismo, por eso al invocar el método y pasar le la cadena con una secuencia ..\\ indicamos al ensamblado que escriba el archivo un nivel arriba.

Más que buscar un culpable a nivel usuario, la pregunta se plantea a nivel código:
¿como podemos evitar que el código realice operaciones para las que no fue diseñado?
La respuesta sin duda alguna es uno de los objetivos del CAS.
Usando CAS podemos evitar que un usuario o un proceso autenticado utilice los métodos del ensamblado para realizar acciones que no están consideradas en la lógica del programa.
Para lograr ese objetivo CAS utiliza permisos encapsulados como objetos que pueden ser usados a nivel de métodos o ensamblados, estos permisos pueden ser de manera declarativa usados como o como atributos dentro del código, en este ejemplo usaremos un permiso de forma declarativa para nuestro método.

Los permisos representan acciones que son revisadas cada vez que el CLR carga el ensamblado para ejecutarse, estos permisos son controlados por el CAS.

UIPermission Controla la manipulación a la interfaz de usuario y el portapapeles.
ResourcePermissionBase Controla el acceso a los recursos de Windows
RegistryPermission Controla el acceso al Registro de Windows
ReflectionPermission Controla el acceso a la funcionalidad de la reflexión proporcionada por el CLR
IsolatedStoragePermission Controla el acceso a isolated storage
FileIOPermission Controla el acceso de escritura o lectura al disco duro
FileDialogPermission Controla el acceso a archivos o carpetas.
EnviromentPermission Controla el acceso a leer, modificar y crear variables de ambiente.

Si ejecutamos nuevamente el código para escribir los estados de cuenta fuera de la carpeta predeterminada con el ensamblado modificado, se mostrará el siguiente error.

Ahora nuestro ensamblado esta protegido por la seguridad del CAS y no depende de la validación que implementen las clases que invoquen sus métodos.

Para habilitar o des habilitar la seguridad del CAS se utiliza la herramienta caspol con el siguiente argumento:
caspol -s on
Siempre es recomendable habilitar la seguridad del CAS.

Para compilar la aplicación:
csc /r:Ensamblado1.dll EstadosCuenta.cs EstadosCuenta.Designer.cs

 Descarga el código fuente

Entendiendo los ensamblados (assemblies)

Una de las caracteristicas más atractivas que ofrece la programación con .NET es la posibilidad de poder construir aplicaciones con diferentes lenguajes, cada compilador para .NET genera un módulo ejecutable conocido como assembly (ensamblado) que contiene instrucciones en un lenguaje llamado CIL (Common Intermediate Language) que es ejecutado por el CLR (Common Language Runtime).
Examinemos pues el siguiente programa en código C#

Lo compilamos:

$ mcs ProgramCS.cs

Esto nos genera un archivo ProgramCS.exe que es el ensamblado ejecutable.
Ahora examinemos el mismo programa en código Visual Basic.

Lo compilamos:

$ vbnc ProgramVB.vb

Igualmente el compilador de VB nos genera un ensamblado ejecutable ProgramVB.exe.
Al ejecutar cualquiera de los dos ensamblados se mostrará el siguiente resultado:

Los ensamblados se clasifican según su uso:

Privados (Private Assembly) son usados solamente por una aplicación, se instalan dentro del mismo directorio o subdirectorio que la aplicación y opcionalmente pueden o no ser firmados con un Strong name.

Compartido (Shared Assembly) Se usan por dos o más aplicaciones en una misma máquina, se instalan dentro del GAC (Global Assembly Cache) y deben ser obligatoriamente firmados por un Strong name.
o según el contenido:
Archivo único (Single-File Assembly) Todo el contenido del ensamblado es empacado en un solo archivo con extensión (.dll) en caso de ser una biblioteca o con extensión (.exe) en caso de ser un ejecutable.
Multiples archivos (Multifile Assembly)Aqui el contenido del ensamblado esta dividido en multiples archivos, siendo estos de códido IL o bien de otros recursos como imágenes o archivos XML.
Los ensamblados únicamente pueden ser ejecutados por el CLR de .NET, por lo que si queremos que este ensamblado funcione en otra máquina esa máquina debe tener instalado Mono en el caso de GNU/Linux o bien Microsoft .NET en el caso de Windows.

En el caso de los códigos anteriores se genero para cada código un ensamblado privado (Private Assembly) y de archivo único (Single File Assembly).

 Descarga el código fuente