viernes, 28 de noviembre de 2014

datagridView con filtros


private void txtDescripcion_TextChanged(object sender, EventArgs e)
        {
            string fieldName = string.Concat("[", dt.Columns[1].ColumnName,"]");
            dt.DefaultView.Sort = fieldName;
            DataView view = dt.DefaultView;
            view.RowFilter = string.Empty;
            if (txtDescripcion.Text != string.Empty)
                view.RowFilter = fieldName + " LIKE '%" + txtDescripcion.Text + "%'";
            dgvCliente.DataSource = view;
        }


lunes, 24 de noviembre de 2014

How can I make the cursor turn to the wait cursor

How can I make the cursor turn to the wait cursor

You can use Cursor.Current.
// Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor;

// Execute your time-intensive hashing code here...

// Set cursor as default arrow
Cursor.Current = Cursors.Default;

Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

Cuando presentamos un conjunto de datos en forma tabular mediante el control DataGridView, hay ocasiones en las que se necesita proporcionar al usuario la posibilidad de realizar ciertas operaciones, en base a uno o varios valores situados en las celdas de una determinada fila del control.
Por ejemplo, en el formulario que vemos en la siguiente imagen se muestra un DataGridView con algunos campos de la tabla DimProduct, perteneciente a la base de datos AdventureWorksDW. El objetivo consiste en que el usuario pueda introducir en el TextBox un valor, que representa un porcentaje de descuento a aplicar sobre el campo ListPrice, de la fila del DataGridView que seleccione.
 
Entre las diversas técnicas disponibles para realizar la operación que acabamos de mencionar, en este artículo vamos a hacer uso de las clases DataGridViewButtonColumn y DataGridViewButtonCell, que combinaremos para crear, dentro del control DataGridView, una nueva columna calculada, cuyas celdas contengan botones, que al ser pulsados, nos permitan realizar una operación con los valores de otras celdas de la fila seleccionada. Como particularidad añadida, los botones de nuestra nueva columna contendrán una imagen.
En primer lugar crearemos, en Visual Studio 2008, un nuevo proyecto de tipo Windows Forms Application, al que daremos el nombre DGVColumnaBotonesImagen, añadiendo al diseñador del formulario los controles mostrados en la anterior imagen.
Seguidamente pasaremos al editor de código del formulario, y en su evento Load escribiremos el siguiente bloque de código, que usaremos para conectarnos a una base de datos y cargar el DataGridView con un subconjunto de los registros de la tabla.
using System.Data.SqlClient;
//....
namespace DGVColumnaBotonesImagen
{
public partial class Form1 : Form
{
    //....

    private void Form1_Load(object sender, EventArgs e)
    {
        SqlConnection cnConexion = new SqlConnection();
        cnConexion.ConnectionString = "Data Source=localhost;" +
            "Initial Catalog=AdventureWorksDW;" +
            "Integrated Security=True";

        string sSQL = "SELECT ProductKey, SpanishProductName, ListPrice " +
            "FROM DimProduct WHERE ListPrice IS NOT NULL";

        SqlCommand cmdComando = new SqlCommand(sSQL, cnConexion);
        SqlDataAdapter daAdaptador = new SqlDataAdapter(cmdComando);
        DataTable tblDimProduct = new DataTable();
        daAdaptador.Fill(tblDimProduct);
        this.dataGridView1.DataSource = tblDimProduct;
        //....
    }
    //....
A continuación definiremos nuestra columna personalizada creando una instancia de la clase DataGridViewButtonColumn, que añadiremos a la colección de columnas del DataGridView.
private void Form1_Load(object sender, EventArgs e)
{
    //....
    DataGridViewButtonColumn colBotones = new DataGridViewButtonColumn();
    colBotones.Name = "colBotones";
    colBotones.HeaderText = "Valor Stock";

    this.dataGridView1.Columns.Add(colBotones);
}
La siguiente imagen muestra el resultado.

El anterior código crea una nueva columna basada en botones, pero estos carecen de contenido. Para incluir una imagen en su interior crearemos un manipulador para el evento CellPainting del control, en el que realizaremos las siguientes operaciones:
En primer lugar comprobaremos si la celda a pintar corresponde a nuestra columna de botones y se encuentra en una fila válida; en caso afirmativo, pintamos la celda ejecutando el método DataGridViewCellPaintingEventArgs.Paint. Seguidamente obtenemos una instancia del botón situado en la celda y otra de la imagen (un icono en este ejemplo) a situar en su interior, dibujando esta mediante el método Graphics.DrawIcon, con un tamaño ligeramente inferior al del botón.
Finalmente, para poder visualizar de forma más adecuada el botón, ajustamos las dimensiones de la fila y columna que lo alojan en función de las dimensiones de la imagen. También debemos asignar el valor true a la propiedad DataGridViewCellPaintingEventArgs.Handled, que nos servirá para que el control tenga en cuenta la implementación que hemos realizado sobre este evento.
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
    if (e.ColumnIndex >= 0 && this.dataGridView1.Columns[e.ColumnIndex].Name == "colBotones" && e.RowIndex >= 0)
    {
        e.Paint(e.CellBounds, DataGridViewPaintParts.All);

        DataGridViewButtonCell celBoton = this.dataGridView1.Rows[e.RowIndex].Cells["colBotones"] as DataGridViewButtonCell;
        Icon icoAtomico = new Icon(Environment.CurrentDirectory + @"\Atomico.ico");
        e.Graphics.DrawIcon(icoAtomico, e.CellBounds.Left + 3, e.CellBounds.Top + 3);

        this.dataGridView1.Rows[e.RowIndex].Height = icoAtomico.Height + 10;
        this.dataGridView1.Columns[e.ColumnIndex].Width = icoAtomico.Width + 10;

        e.Handled = true;
    }
}
En la siguiente imagen podemos ver el control con la columna resultante, incluyendo los botones con el icono.

Tan sólo resta añadir al botón la lógica que efectúe el cálculo del descuento comentado al comienzo del artículo, aspecto este que resolveremos codificando el evento CellClick del DataGridView. Al producirse este evento comprobaremos si existe valor en el TextBox del formulario, y en caso afirmativo, nos cercioraremos de que la celda sobre la que se ha realizado la pulsación corresponde a nuestra columna calculada, si esto se cumple, procederemos con el cálculo, mostrándolo en una caja de mensaje.
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
    if (this.txtPorcentaje.Text == string.Empty)
    {
        MessageBox.Show("Introducir valor para el porcentaje");
        this.txtPorcentaje.Focus();
    }
    else
    {
        if (this.dataGridView1.Columns[e.ColumnIndex].Name == "colBotones")
        {
            decimal nListPrice = (decimal)this.dataGridView1.Rows[e.RowIndex].Cells["ListPrice"].Value;
            int nPorcentaje = int.Parse(this.txtPorcentaje.Text);
            decimal nDescuento = (nListPrice * nPorcentaje) / 100;

            MessageBox.Show(nDescuento.ToString("#,#.##"), "Descuento aplicable");
        }
    }
}
La siguiente imagen muestra el resultado de una operación.
 
Utilizando el control DataGridView, en este artículo hemos explicado una técnica, que de manera sencilla nos permite crear una columna conteniendo botones que muestran un icono en su interior, lo cual nos puede servir para dar una mejor apariencia a nuestros controles de cuadrícula. En los siguientes enlaces:  C# y VB, disponemos del proyecto de ejemplo. Espero que os resulte de utilidad.
Un saludo.
Published 16/9/2009 21:24 por Luis Miguel Blanco
Archivado en:
Comparte este post:    

Comentarios

Saturday, September 19, 2009 1:14 PM por El aprendiz de brujo

# DataGridViewColumn y DataGridViewCell. Creación de columnas personalizadas para el control DataGridView (1)

Crear para el control DataGridView, una columna cuyas celdas contengan botones, los cuales realicen una
Wednesday, November 4, 2009 1:02 AM por danny

# re: Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

hola muchas gracias la verdad me ha servido mucho tu ejemplo, es justo lo que buscaba, nada más que me gustaría saber si en lugar de poner un icono, podria yo poner texto yo lo quiero para que el botón diga 'Edit' ok?
te agradeceria que me dijeras como
muchas gracias de antemano.
Wednesday, November 11, 2009 11:01 PM por Luis Miguel Blanco

# re: Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

Hola Danny
Puedes utilizar el método Graphics.DrawString para dibujar un texto dentro del botón, de forma similar a como puedes ver en el siguiente bloque de código:
//-----------------------------------
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
   if (e.ColumnIndex >= 0 && this.dataGridView1.Columns[e.ColumnIndex].Name == "colBotones" && e.RowIndex >= 0)
   {
       e.Paint(e.CellBounds, DataGridViewPaintParts.All);
       DataGridViewButtonCell celBoton = this.dataGridView1.Rows[e.RowIndex].Cells["colBotones"] as DataGridViewButtonCell;
       e.Graphics.DrawString("Edit", new Font("Verdana",8),new SolidBrush(Color.Black),
           e.CellBounds.Left + 3, e.CellBounds.Top + 3);
       e.Handled = true;
   }
}
//-----------------------------------
Un saludo.
Luismi
Wednesday, January 20, 2010 11:35 AM por Vicenç

# re: Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

Hola Luismi,
gracias por el artículo, me ha sido muy útil. Yo lo que estoy haciendo es una columna con botones ( en un datagrid no asociado a un datasource, sólo son 4 filas ) con un botón con un texto ( de momento, quizá en un futuro va una imagen ). El tema es que en una de las filas no quiero mostrar el botón. Cómo lo podria ocultar?
Muchas gracias,
Vicenç
Sunday, January 24, 2010 7:02 PM por Luis Miguel Blanco

# re: Crear una columna de botones con imagen usando la clase DataGridViewButtonColumn

Hola Vicenç
Gracias por tu opinión y por el interés en el artículo. Sobre tu comentario acerca de ocultar un botón, hay que tener en cuenta que cuando añadimos a un DataGridView una columna de tipo DataGridViewButtonColumn, al ejecutar la aplicación, el DataGridView se mostrará con esa columna llena de botones, aunque estén vacíos, sin imagen o texto, ya que el comportamiento base de la clase DataGridViewButtonColumn es la creación de dicha columna rellena de botones, luego tú los puedes personalizar como quieras: añadiendo texto o imagen como se explica en el artículo del blog.
Si quieres ir más allá en la personalización de una columna de estas características, es posible que tengas que utilizar algo similar a lo que se explica en la serie de artículos que puedes encontrar en el siguiente enlace:
geeks.ms/.../datagridviewcolumn-y-datagridviewcell-creaci-243-n-de-columnas-personalizadas-para-el-control-datagridview-1.aspx
Aquí se explica el modo de creación de una columna y celdas partiendo de cero, requiere más trabajo pero es más personalizable.
Espero que te resulte de utilidad.
Un saludo.
Luismi

domingo, 23 de noviembre de 2014

SELECCIONAR FECHAS EN ORACLE

SELECCIONAR FECHAS EN ORACLE

SELECT *
      FROM RHH_MARCACIONES
     WHERE TRUNC (FECHA_MARCACION) = TO_DATE ('23-11-2014', 'DD-MM-YYYY HH24-MI-SS')

jueves, 6 de noviembre de 2014

conexion reota oracle

Solución Conexión Remota Oracle XE (APEX)

Posted by Paola Pullas | Posted in Aplicaciones, Oracle XE | Posted on 09-07-2007

16

Por: Christian Pazmiño
Después de revisar algunos de los comentarios que se ha publicado en el ecuoug.org, me he dado cuenta que hay algunos problemas recurrentes y que mejor deberíamos tratarlos como un post nuevo, no solo voy a tratar este problema sino que voy a ir solucionando algunos de los problemas que están en los comentarios que mas me han llamado la atención y además que son divertidos de solucionar, con esto no estoy diciendo que todos los problemas que han tenido no los vamos a resolver, pero si hay unos que me gustan mas y que les voy a dar mayor prioridad.
Por ahora estoy en conversaciones con la Big Boss y estoy gestionando para que volvamos a subir el Foro de ECUOUG donde creo que es un mejor lugar para ir solucionando los problemas que vayamos teniendo, pero después de la mala experiencia que tuvimos con el anterior foro que se lleno de SPAM estamos aun medios temerosos. Sin mas aquí va la solución para las personas que no puede conectarse remotamente a nuestro APEX.
Oracle XE tiene unas políticas de seguridad bastante interesantes por lo que han decidido no permitir conexiones remotas por defecto, lo que debemos hacer es conectarnos vía sqlplus como SYSTEM, ya dentro de sqlplus, debemos ingresar la siguiente sentencia:
SQL> exec dbms_xdb.setListenerLocalAccess(false);
y eso es todo ahora podremos conectarnos a nuestro APEX específicamente remotamente desde un Web browser.
Por ejemplo si nuestro servidor de base de datos tiene la siguiente dirección 192.168.0.100, específicamente ingresar con la siguiente URL:
http://192.168.0.100:8080/apex
Eso es todo por ahora, más tarde seguiré subiendo las soluciones para otros problemas que he encontrado en los distintos comentarios.


miércoles, 5 de noviembre de 2014

Conexion Oracle por App.config

conexion Oracle con App.config

Implementando Aplicaciones .NET con ODP.NET & Entity Framework

Por Francisco Riccio
Publicado en marzo 2013
Introducción
Este material está dedicado a detallar algunos conceptos básicos de la arquitectura ADO .NET de Microsoft llevados hacia las aplicaciones que interactúan con la base de datos Oracle.
ADO.NET es la capa dentro de .NET Framework que permite interactuar a las aplicaciones con un motor relacional, tiene especificado una serie de interfaces que todo proveedor de base de datos debe implementar si desea que su tecnología de base de datos pueda integrarse a las aplicaciones de Microsoft .NET.
Se adjunta la arquitectura de ADO.NET:
 arquitectura de ADO.NET
En la arquitectura de ADO.NET se puede trabajar con los datos de manera conectada y desconectada con la base de datos. La clase de que nos permite trabajar de manera conectada es el DataReader el cual será el que se usará en este documento y de manera desconectada se realiza a través de las clases: DataAdapter y DataSet. La clase DataSet almacena información obtenida de la base de datos extraída mediante la clase DataAdapter.
Recomiendo la lectura a la siguiente página web para obtener mayor detalle de ADO.NET:
http://msdn.microsoft.com/en-us/library/e80y5yhx.aspx
Microsoft cuenta con una librería llamada Microsoft Oracle Client como parte de .NET Framework. Esta librería implementa la interfaz de ADO.NET para conectarse a la base de datos Oracle. Oracle Corporation también liberó una librería conocida como ODP.NET entregando mejores resultados de performance y ventajas sobre Microsoft Oracle Client, aprovechando todos la gran mayoría de features de la base de datos directamente.
En la siguiente dirección web se detallan las ventajas entre ODP.NET vs Microsoft Oracle Client:
http://www.oracle.com/technetwork/topics/dotnet/index-154765.html
Cabe mencionar que Microsoft Oracle Client permite implementar aplicaciones con conexión de base de datos Oracle versión 8.1.7 hacia adelante y viene a través del namespace System.Data.OracleClient.
ODP.NET está disponible su descarga gratuitamente en la página oficial de Oracle que se adjunta:
http://www.oracle.com/technetwork/developer-tools/visual-studio/downloads/index.html
Una parte del material estará enfocado a desarrollar un ejemplo de cómo trabajar con ODP.NET para realizar un mantenimiento a una tabla de base de datos Oracle y asimismo la segunda parte del documento implementará el mismo mantenimiento utilizando Entity Framework y LINQ de manera práctica.
Entity Framework es un conjunto de tecnologías diseñadas para desarrollar aplicaciones que accedan a la información en un modelo de aplicaciones conceptual basado en un modelo de objetos y no enfocado a tablas de un modelo relacional. Un similar framework a esté en el mercado es NHibernate.
La manera de como se manipula la información en este tipo de modelo se realiza no mediante sentencias SQL sino a través del lenguaje LINQ. LINQ se encarga de traducir nuestro requerimiento a la sintaxis propia del motor de base de datos donde se conecta.
Ambas implementaciones se han realizado en una configuración con Oracle Database 11g (11.2.0.3) en plataforma Oracle Linux 32 bits y .NET Framework 4.0 con ODP.NET 4. El IDE de desarrollo para las implementaciones es sobre Visual Studio 2010 basado en el lenguaje C#.
Se asume que el lector ha tenido experiencia previa con Visual Studio en la construcción de aplicaciones .NET con acceso a datos; si no fuera el caso recomiendo la revisión de la siguiente página web como referencia:
http://www.oracle.com/technetwork/es/articles/dotnet/cook-dotnet-083575-esa.html
Implementación ODP.NET
El objetivo del siguiente programa a implementar es construir una aplicación .NET que pueda dar mantenimiento a la tabla PRODUCTO la cual reside en la base de datos Oracle.
Se presenta la estructura de la tabla PRODUCTO acompañado de su script de creación.
tabla PRODUCTO
Figura 2
SQL> create table PRODUCTO (id number, descripcion varchar(20), pu number, registrado date);
La arquitectura que tendrá la aplicación está basado en un modelo de tres capas las cuales son: Capa de Acceso a datos encargada de acceder a la fuente de datos provista en este caso con ODP.NET, Lógica de Negocio la cual lleva la implementación de los escenarios y reglas del negocio y la capa de Presentación que podría ser un programa de escritorio, web o móvil. En nuestra implementación se realizará una aplicación de escritorio. La manera de como se lleva la información entre las capas presentadas se realiza mediante la librería Entidades. La librería Entidades lleva la información almacenada en la base de datos mediante objetos entre las diferentes capas mencionadas.
Este tipo de arquitectura nos permite tener una aplicación flexible a cambios y de fácil mantenimiento y soporte.
Se adjunta un gráfico de los componentes mencionados.
tipo de arquitectura
Figura 3
Donde en el Visual Studio se representará en 4 proyectos como se muestra:
Visual Studio
La interfaz de la pantalla de mantenimiento de la tabla Producto tendrá la siguiente forma:
interfaz de la pantalla
Figura 5
Se detallará el desarrollo de la capa de Acceso a Datos (DAO) mediante la implementación de ADO.NET con ODP.NET.
Capa DAO
Para su implementación se realizó las siguientes actividades:
a) Debemos crear un nuevo proyecto de tipo Class Library, ejemplo:
crear un nuevo proyecto de tipo Class Library
Figura 5
b) Al nuevo Class Library agregado le añadimos la librería de ODP.NET (Oracle.DataAccess).
añadimos la librería de ODP.NET
Figura 6
Nota: Esta librería aparecerá en nuestro Visual Studio cuando instalemos ODP.NET sobre la estación de desarrollo.
c) La librería DAO tendrá dos clases: Conexion y ProductoDAO.
Conexion y ProductoDAO
Figura 7
La clase Conexion se encarga de generar la conexión hacia la base de datos y la clase ProductoDAO implementa las operaciones de mantenimiento a la tabla Producto.
d) Se detalla la implementación de la clase Conexión.
implementación de la clase Conexión
Donde se observa lo siguiente:
  • La clase conexión de ODP.NET que nos permite conectarnos a la base de datos se llama OracleConnection el cual está en el namespace Oracle.DataAccessClient.
  • La clase OracleConnection recibe la cadena de conexión cuya especificación está almacenada en la configuración de la aplicación (App.config).
OracleConnection
Figura 8
El contenido del archivo es:
<?xml version="1.0" encoding="utf-8" ?>>
<configuration>  
  <appSettings>
    <add key="CONEXION" value="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)
(HOST=142.68.1.20)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)));
User Id=FRICCIO;Password=oracle;Enlist=false;Pooling=true"/>
  </appSettings>
</configuration>

El atributo Pooling de la conexión de la base de datos permite que la aplicación no esté creando una conexión física a la base de datos en cada solicitud que se necesite una conexión, por tal motivo la conexión se crea una vez y se mantiene establecida en la base de datos con mínimos recursos utilizados en la base de datos. Por default su valor es true y se recomienda dejarlo en ese valor.
El atributo Enlist permite que las operaciones DML que se ejecutan mediante la conexión establecida se trabajen como parte de una transacción distribuida. Si no fuera nuestro caso, se debe colocar el valor de false ya que por default tiene el valor de true.
http://www.connectionstrings.com/oracle
e) Se detalla la implementación de la clase ProductoDAO.
ProductoDAO
Se puede observar que la clase implementa una función para obtener la lista de Productos almacenados en la base de datos y sus tres operaciones de mantenimiento (insertar/eliminar/modificar).
La clase utiliza los namespaces: Oracle.DataAccess.Client y Oracle.DataAccess.Types.
Implementación de la función que obtiene la lista de Productos:
La función getProductos devuelve un arreglo que contiene los productos almacenados en la tabla Producto. Cada elemento del arreglo es un objeto de la clase EProducto de la librería Entidades.
Se adjunta la implementación de la clase EProducto de la librería Entidades:
EProducto
Figura 9
EProducto
La función utiliza el stored procedure spu_listarProductos para obtener la lista de productos.
Se adjunta la implementación del Stored Procedure spu_listarProductos:
create or replace procedure spu_listarProductos (pcursor out sys_refcursor)
is
begin
 open pcursor for
  select id,descripcion,pu,registrado
  from producto;  
end;
/

El stored procedure recibe un parámetro de salida (out) de tipo sys_refcursor.
El curso es abierto dentro del stored procedure y las operaciones de fetch serán ejecutadas en la capa de aplicación y cuya responsabilidad será cerrarlo.
Es recomendable que las consultas y las operaciones DML sean implementadas mediante stored procedures ya que entrega mejor performance.
En la siguiente página se detalla la implementación de la clase y como podríamos consumir el stored procedure presentado.
 implementación de la clase
Donde:
  • La función obtiene una conexión mediante la clase Conexion y con dicho objeto se creará el objeto command (OracleCommand).
  • La clase OracleCommand permite ejecutar código SQL & PLSQL directamente desde la aplicación como stored procedures. Para esta acción se define que ejecutaremos un stored procedure e indicamos el procedimiento almacenado a ejecutar.
  • Debido a que el stored procedure recibe un parámetro de salida creamos un objeto de tipo OracleParameter y lo definimos que será de salida y de tipo RefCursor.
  • El método executeNonQuery ejecuta el stored procedure y éste nos devolverá el cursor ya abierto el cual tiene identificado el conjunto de filas a recuperar.
  • Se crea el objeto DataReader mediante el valor obtenido por el cursor (OracleParameter) para recorrer la información y cargarla a nuestro arreglo de Productos.
  • Un fetch es un conjunto de filas que recoge la capa de aplicación de la base de datos mientras recorre un cursor. Por default este valor es 64 KB, es decir en bloques de 64 KB se va obteniendo todas las filas de un cursor.

    En muchas situaciones es recomendable aumentar el tamaño en ventaja de recoger la información más rápido siendo más eficientes. Esto se realiza con la siguiente línea de código:

    dr.FetchSize = cmd.RowSize * 100;

    En este caso esperamos recibir la información en bloques de 100 filas, por lo cual si una tabla tiene 1000 filas se harán 10 viajes de la capa de base de datos a la capa cliente para obtener la información completa de la tabla.

    La vista V$SQL tiene los campos: executions, fetches y rows_processed los cuales nos pueden ayudar a definir la cantidad de filas hacer retornadas en un fetch de manera eficiente. Por ejemplo: Si obtenemos el ratio de rows_processed/executions nos daría la cantidad de filas promedio obtenidas en una ejecución del query. El ratio de fetches/executions nos entrega la cantidad de fetchs en cada ejecución. Obteniendo ambos ratios tenemos la cantidad de filas y fetchs de cada ejecución del query los cuales podrían ser reducidos ampliando la cantidad de filas a traer en cada operación de fetch.

    Existe un bug con el atributo RowSize del objeto Command ya que devuelve siempre el valor de 0. Para evitar el bug y conseguir el tamaño en bytes de una fila se ha implementado las siguientes líneas de código.
     implementación de la clase
Nota 1: En caso siempre una consulta retorne una sola fila con un solo campo es recomendable usar el método ExecuteScalar del objeto OracleCommand, ya que está diseñado a este tipo de escenario entregando mejor performance.
Nota 2: La forma de trabajar con los datos fueron de manera conectada en la función getProductos. La manera desconectada se recomienda cuando queramos crear reportes que realizan operaciones de join entre múltiples tablas, donde la información se almacenará en objetos DataSet.
Implementación del procedimiento insertar:
Se ha diseñado este procedimiento para que ejecute la operación insert desde la capa de aplicación y no mediante un stored procedure. El objetivo es demostrar como ejecutar sentencias desde la capa de aplicación, más no sería lo más óptimo.
Implementación del procedimiento insertar
A diferencia del caso anterior, aquí el objeto OracleCommand se configura para recibir una sentencia (System.Data.CommandType.Text). La sentencia recibe los parámetros :PID,:PDESCRIPCION,:PPU,:PDESCRIPCION que más adelante son especificados con sus tipos de datos y valores.
Nota: Es recomendable que la sentencia SQL utilice parámetros para que diferentes valores que adopten los parámetros, Oracle Database no cree un plan de ejecución por cada uno de ellos, haciendo que nuestra memoria del Shared Pool de la base de datos sea ineficiente. Usando parámetros evitamos hard parsing en la base de datos.
Si deseamos evitar soft parsing, debemos mantener cursores en cache en la capa de aplicación evitando repetido procesamiento de metadata. Para realizar esta labor debemos habilitar el cache de sentencias en la cadena de conexión.
En nuestro ejemplo deberíamos agregar la cláusula "Statement Cache Size" a la cadena de conexión como se adjunta en el siguiente ejemplo:
Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=142.68.1.20)(PORT=1521)))
(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=orcl)));
User Id=FRICCIO;Password=oracle;Enlist=false;Pooling=true; Statement Cache Size=50;
El valor por default es 10.
Implementación del procedimiento eliminar:
Este procedimiento se ejecuta el stored procedure spu_eliminarProducto el cual se detalla a continuación:
create or replace procedure spu_eliminarProducto (pid number)
is
begin
 delete 
 from producto
 where id=pid;
end;
/

Podemos observar que la confirmación de la transacción no se ha especificado en el código del Stored Procedure porque como buena práctica dicha confirmación debe venir de la capa de aplicación. Por default la conexión establece la propiedad autocommit; es decir terminado una ejecución de una operación DML automáticamente se confirma.
Nota: Una buena práctica es que la confirmación de la operación DML sea declarativo y no esté configurado en autocommit.
En el ejemplo de eliminar un producto se confirma la transacción mediante la propiedad autocommit.
Se adjunta la implementación del procedimiento eliminar de la clase ProductoDAO:
Implementación del procedimiento eliminar
Implementación del procedimiento modificar:
Este procedimiento se ejecuta el stored procedure spu_modificarProducto el cual se detalla a continuación:
create or replace procedure spu_modificarProducto (pid number, pdescripcion varchar, 
ppu number, pregistrado date)
is
begin
 update producto
 set descripcion=pdescripcion, pu=ppu, registrado=pregistrado
 where id=pid;
end;
/

En esta ocasión la confirmación de la operación UPDATE no se ejecutará con la propiedad autocommit que es lo más recomendable.
confirmación de la operación UPDATE
Para lograr con el objetivo de no utilizar la propiedad autocommit debemos crear un objeto de la clase OracleTransaction y puntualmente debemos ejecutar el procedimiento commit si deseamos confirmar la transacción de un conjunto de operaciones DML que pudiera ejecutar el OracleCommand o el procedimiento rollback si deseamos cancelar.
Nota: ODP.NET nos permite configurar algunos aspectos de globalización de las conexiones que apertura la aplicación hacia la base de datos. Esto lo realizamos a través de la clase OracleGlobalization. En el ejemplo se modifica el formato de fecha y el calendario para las conexiones de base de datos que ha realizado la aplicación.
OracleGlobalization objGlobal = OracleGlobalization.GetClientInfo();
objGlobal.DateFormat="DD/MON/YYYY";
objGlobal.Calendar="Persian";
OracleGlobalization.SetThreadInfo(objGlobal);

Implementación Entity Framework & LINQ
Para implementar Entity Framework sobre el manejo de una base de datos Oracle debemos contar con Oracle Developer Tools versión 11.2.0.2.40 o superior para Visual Studio.
La implementación a realizar mantiene la misma arquitectura de software presentada en la anterior implementación únicamente la librería de acceso a datos será modificada para ajustarla a Entity Framework.
A continuación se detallará el desarrollo de la implementación.
a) El primer requisito para trabajar con Entity Framework es que nuestras tablas cuenten con primary key en su diseño.
b) Sobre la librería de acceso a datos agregamos un elemento ADO.NET Entity Data Model como se muestra:
 ADO.NET Entity Data Model
Figura 10
c) Luego traeremos de la base de datos el modelo lógico.

Figura 11
base de datos
Figura 12
base de datos
Figura 13
Nota: La clase controladora que nos permitirá trabajar con todo el esquema de Entity Framework acorde a la configuración realizada será Entidades.
Al finalizar la configuración de Entity Framework veremos el diseño de la clase PRODUCTO que representa la tabla Producto de nuestra base de datos.
PRODUCTO
Figura 14
Nuestra librería de Acceso a Datos debería visualizarse de la siguiente manera:
librería de Acceso a Datos
Figura 15
Podemos apreciar que Entity Framework nos ha creado el archivo App.config, el cual lleva la información de la cadena de conexión hacia la base de datos.
Debemos posteriormente agregar la librería System.Data.Entity en el componente de Acceso a Datos.
librería System.Data.Entity
Figura 16
c) Se configurará las propiedades para realizar los mantenimientos a la tabla Producto.
Entity Framework nos provee todo un código ya implementado para realizar el mantenimiento (insert/delete/update) a cada entidad, pero podría ser reemplazado por stored procedures que realicen está labor en pro de conseguir mejor performance.
Para esta labor se reutilizará los stored procedures existentes en la anterior implementación. La única operación a implementar será el INSERT que no estaba realizado hasta este punto.
create or replace procedure spu_insertarProducto (ppid number, pdescripcion varchar, ppu number, 
pregistrado date)

is
begin
 insert into producto(id,descripcion,pu,registrado) values (ppid,pdescripcion,ppu,pregistrado);
end;
/

Sobre las propiedades de la clase PRODUCTO de Entity Framework seleccionamos la opción Stored Procedure Mapping.
clase PRODUCTO de Entity Framework
Figura 17
Y en la parte inferior relacionaremos cada operación DML a su stored procedure que ejecutará la acción.
Ejemplo:
operación DML
Figura 18
Es importante la operación de UPDATE tenga marcado la propiedad "Use Original Value" para los campos que conforman el primary key de esa entidad.
Nota: Si optamos utilizar stored procedures, las tres operaciones (insert/delete/update) deben implementarse con procedimientos almacenados obligatoriamente.
d) Se presentará las operaciones DML desde la clase ProductoDAO como se realizó en la anterior implementación pero utilizando Entity Framework.
Operación INSERT:
Operación INSERT
Donde en el código presentado se crea un objeto CTX de la clase Entidades cuya función será ser el coordinador con las entidades que podamos haber traído de la base de datos para ejecutar operaciones.
En este caso el objeto CTX solicita almacenar un objeto PRODUCTO en la base de datos mediante las operaciones AddToPRODUCTO y SaveChanges.
Operación DELETE y UPDATE:
Operación DELETE y UPDATE
En ambos casos solicitamos al objeto coordinador (CTX) que nos devuelva el objeto PRODUCTO a eliminar o modificar. La forma de como se lo solicitamos es mediante el lenguaje LINQ. LINQ es transparente sobre qué motor de base de datos se ejecutará.
La operación delete solicitará la eliminación del objeto mediante el método DeleteObject y SaveChanges y en el caso de la operación Update cualquier cambio en los atributos del objeto Producto serán almacenados en la base datos mediante el método SaveChanges.
En las tres operaciones básicas el objeto coordinador CTX solicitará la ejecución de los stored procedures relacionados a cada operación.
e) Ejecutando otras operaciones.
A continuación se detallará diferentes ejemplos de cómo utilizar EntityFramework con LINQ:
e.1) Obtener la relación completa de productos.
relación completa de productos
El objeto coordinador CTX con la función PRODUCTO.ToList() nos devuelve un arreglo de PRODUCTOS. Por un tema de diseño estoy transformando la lista de objetos PRODUCTOS a una lista de EPRODUCTOS con la intención de no modificar la capa de Negocio y Presentación de nuestro sistema.
e.2) Obtener un Producto mediante su ID.
Obtener un Producto mediante su ID
Al objeto coordinador CTX se le solicita la ejecución del siguiente query de LINQ:
(from PROD in ctx.PRODUCTO.ToList() where PROD.ID == id select PROD).FirstOrDefault()
Donde filtramos de la lista de Productos (ctx.PRODUCTO.ToList()) aquel objeto que tenga en su atributo ID el valor que estamos buscando. El query espera devolver un arreglo como respuesta a la consulta, pero la operación FirstOrDefault() hará que se devuelva el primer objeto del arreglo por lo cual se devuelve un solo objeto PRODUCTO.
e.3) Utilizando LINQ con las operaciones ORDER BY y GROUP BY.
operaciones ORDER BY y GROUP BY
Al objeto coordinador CTX se le solicita la lista de productos cuyo precio unitario es mayor a 0 y su descripción contenga la letra V, el resultado de esta información será ordenada por el campo ID, el resultado se le asigna a la variable lista.
La lista obtenida se le aplicará nuevamente una consulta LINQ solicitando que la lista sea agrupada por el campo registrado obteniendo en cada fecha de registro, la cantidad de productos registrados en ese mismo momento de tiempo, similar a un query como este: SQL> select registrado, count(*) from producto group by registro;
El resultado de esta consulta LINQ sobre la lista es transferida a la variable listaAgrupada definida como var. Las variables definidas con la cláusula var indica que en tiempo de ejecución, la variable obtendrá el tipo de dato que corresponde, en este caso la variable listaAgrupada será un arreglo donde cada elemento se conformará de dos campos.
Posterior la información listaAgrupada es copiada a un DataTable con la finalidad de enviarlo a la capa de Negocio. Por temas de diseño copio el resultado devuelto por LINQ a un DataTable al no contar con una entidad de negocio que represente el reporte que hemos realizado en caso contrario tendría que estar creando Entidades de Negocio por cada reporte que pudiera tener la aplicación, no sería mantenible en el tiempo.
Nota 1: Se puede apreciar que el lenguaje LINQ no solo lo podemos utilizar en Entity Framework sino en cualquier escenario donde manejos arreglos.
Nota 2: Ejecutar operaciones ORDER BY o GROUP BY sobre la base de datos muchas veces tiene un alto costo, podemos evaluar utilizar LINQ para realizar estas labores en la capa de aplicación, liberando recursos en la base de datos. Por experiencia realizar estas labores en la aplicación ha entregado mejores tiempos que realizarlo en la misma base de datos
e.4) Utilización de Stored Procedures
Entity Framework nos permite ejecutar stored procedures que pudieran tener acciones específicas. No está soportado el uso de funciones PLSQL.
Ejemplos:
e.4.1) Se desea obtener el la suma de los precios unitarios de todos los productos registrados en la base de datos.
Al no poder utilizar funciones PLSQL en Entity Framework creamos un stored procedure que devuelva mediante un parámetro de tipo out el cálculo solicitado.
Ejemplo:
create or replace procedure spu_sumarPU(ptotal out number)
is
 v_total number;
begin
 select sum(pu) into v_total from producto;
 ptotal:=v_total;
end;
/

Para registrar el stored procedure en la clase PRODUCTO de Entity Framework ejecutamos los siguientes pasos:
  • Botón derecho sobre el modelo de Entity Framework y seleccionamos Add->Function Import.
    Function Import
    Figura 19
  • Luego visualizaremos la siguiente pantalla escogiendo el stored procedure creado y adicional debemos darle un nombre el cual servirá para llamarlo desde el objeto coordinador CTX. Seleccionamos la opción None en Returns a Collection Of porque no se devuelve ninguna colección. simplemente el stored procedure retorna un tipo de dato number.
    stored procedure
    Figura 20
  • Invocando el stored procedure registrado.
    Invocando el stored procedure
e.4.2) Se desea obtener una lista que contenga la siguiente información: descripción, precio unitario y precio con descuento de cada producto.
Se adjunta el stored procedure que resuelve la solicitud:
create or replace procedure spu_getDescripcionPU(pcursor out sys_refcursor)
is
begin
 open pcursor for
  select descripcion, pu, pu*0.5 as pu_dsct
 from producto;  
end;
/

Para registrar este stored procedure en la clase PRODUCTO de Entity Framework ejecutamos los siguientes pasos:
• El stored procedure al no devolver un tipo de dato simple para Entity Framework (Entero/Cadena/Fecha) debemos indicar los campos que devolverá el cursor con sus tipos de datos en el archivo App.config.
En nuestro caso, el cursor devuelve tres campos: descripción, precio unitario y precio con descuento.
Por lo cual el app.config tendría el siguiente contenido:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="Entidades" connectionString="metadata=res://*/BDOracle.csdl|res://*/BDOracle.ssdl|res://*/
BDOracle.msl;provider=Oracle.DataAccess.Client;provider connection string="DATA SOURCE=;PASSWORD=oracle;
USER ID=FRICCIO"" providerName="System.Data.EntityClient" />    
  </connectionStrings>
  <oracle.dataaccess.client>
    <settings>
      <add name="FRICCIO.SPU_GETDESCRIPCIONPU.RefCursor.PCURSOR" value="implicitRefCursor 
bindinfo='mode=Output'" />
      <add name="FRICCIO.SPU_GETDESCRIPCIONPU.RefCursorMetaData.PCURSOR.Column.0" 
value="implicitRefCursor metadata='ColumnName=descripcion;BaseColumnName=DESCRIPCION;
BaseSchemaName=FRICCIO;BaseTableName=PRODUCTO;NATIVEDATATYPE=Varchar2;ProviderType=Varchar2'" />
      <add name="FRICCIO.SPU_GETDESCRIPCIONPU.RefCursorMetaData.PCURSOR.Column.1" 
value="implicitRefCursor metadata='ColumnName=pu;BaseColumnName=PU;BaseSchemaName=FRICCIO;
BaseTableName=PRODUCTO;NATIVEDATATYPE=Number;ProviderType=Decimal'" />
      <add name="FRICCIO.SPU_GETDESCRIPCIONPU.RefCursorMetaData.PCURSOR.Column.2" 
value="implicitRefCursor metadata='ColumnName=pu_dsct;NATIVEDATATYPE=Number;ProviderType=Int32'" />
    </settings>
  </oracle.dataaccess.client>
</configuration>

En este caso, podemos apreciar que primero definimos el parámetro de retorno de tipo RefCursor y luego entramos en detalle sobre las columnas que devolverá el cursor.
En el caso de las dos primeras columnas (descripción y precio unitario) directamente se le relaciona con los campos originales de la tabla Producto pero en el caso del campo precio descuento al ser un campo calculado no se le relaciona a ningún campo de ninguna tabla.
tabla Producto Ejecutamos los mismos pasos como el caso anterior para registrar el stored procedure con la diferencia que damos clic en el botón Get Column Information para que recupere la información que devolverá el cursor, asimismo marcamos la opción Complex ya que estamos devolviendo un tipo de dato compuesto en un arreglo.
marcamos la opción Complex
Figura 21
• Invocando el stored procedure registrado.
stored procedure Nota:Entity Framework solo trabajará con el primer cursor out declarado en un stored procedure, si hubieran más cursores out serán ignorados.
Conclusión
Durante todos los ejemplos revisados se ha visto una gran compatibilidad entre la base de datos Oracle y Microsoft .NET Framework gracias a la librería ODP.NET que comunica ambas tecnologías.
Se pudo apreciar que ODP.NET nos permite crear aplicaciones escalables aprovechando la gran mayoría de features que ofrece la base de datos Oracle además de ofrecer el soporte completo al diseño de desarrollo de software orientado al mapeo de objetos relacionales (ORM) y su persistencia tal como lo hace Entity Framework e implementar lenguajes de consulta como LINQ como complemento a esta tecnología.

Publicado por Ing. Francisco Riccio. Es un IT Specialist en IBM Perú e instructor de cursos oficiales de certificación Oracle. Está reconocido por Oracle como un Oracle ACE y certificado en productos de Oracle Application & Base de Datos.
 

privilegios en Oracle

privilegios Oracle

ORACLE USUARIOS - GRANT

IExplorer bookmarks rss

Grant (dar permisos)

Esta sentencia sirve para dar permisos (o privilegios) a un usuario o a un rol.
Un permiso, en oracle, es un derecho a ejecutar un sentencia (system privileges) o a acceder a un objeto de otro usuario (object privileges).
El conjunto de permisos es fijo, esto quiere decir que no se pueden crear nuevos tipos de permisos.
Si un permiso se asigna a rol especial PUBLIC significa que puede ser ejecutado por todos los usuarios.
Permisos para acceder a la base de datos (permiso de sistema):
GRANT CREATE SESSION TO miusuario;
Permisos para usuario de modificación de datos (permiso sobre objeto):
GRANT SELECT, INSERT, UPDATE, DELETE ON T_PEDIDOS TO miusuario;
Permisos de solo lectura para todos:
GRANT SELECT ON T_PEDIDOS TO PUBLIC;

Permisos de sistema (system privileges)

Los permisos de sistema mas importantes son CREATE SESSION, CREATE TABLE, CREATE VIEW, CREATE USER, ...
Sintaxis:
   GRANT system_priv(s) TO {user, | role, |PUBLIC} 
                  [IDENTIFIED BY password] [WITH ADMIN OPTION]
   GRANT role TO {user, | role, |PUBLIC} 
                  [IDENTIFIED BY password] [WITH ADMIN OPTION]
   GRANT ALL PRIVILEGES TO {user, | role, |PUBLIC} 
                  [IDENTIFIED BY password] [WITH ADMIN OPTION]
Podemos obtener la lista de permisos del sistema asi:
select * from system_privilege_map;
Los permisos de sistema son auditables.
GRANT CREATE SESSION, CREATE TABLE, CREATE VIEW, CREATE PROCEDURE,CREATE SYNONYM,
      ALTER TABLE, ALTER VIEW, ALTER PROCEDURE,ALTER SYNONYM,
      DROP TABLE, DROP VIEW, DROP PROCEDURE,DROP SYNONYM TO programador;

Permisos sobre objetos (object privileges)

Los permisos sobre objetos mas importantes son: SELECT, UPDATE, INSERT, DELETE, ALTER, DEBUG, EXECUTE, INDEX, REFERENCES
   GRANT object_priv [(column, column,...)]
      ON [schema.]object
         TO {user, | role, |PUBLIC} [WITH GRANT OPTION] [WITH HIERARCHY OPTION]
   GRANT ALL PRIVILEGES [(column, column,...)]
      ON [schema.]object
         TO {user, | role, |PUBLIC} [WITH GRANT OPTION] [WITH HIERARCHY OPTION]
   GRANT object_priv [(column, column,...)]
      ON DIRECTORY directory_name
         TO {user, | role, |PUBLIC} [WITH GRANT OPTION] [WITH HIERARCHY OPTION]
   GRANT object_priv [(column, column,...)]
      ON JAVA [RE]SOURCE [schema.]object
         TO {user, | role, |PUBLIC} [WITH GRANT OPTION] [WITH HIERARCHY OPTION]
Con la opcion WITH HIERARCHY OPTION damos permisos sobre todos los subojetos, incluso sobre los que se creen despues de ejecutar el GRANT.
Con la opción WITH GRANT OPTION damos permiso para que el que los recibe los pueda a su vez asignar a otros usuarios y roles.
La opción "GRANT ALL PRIVILEGES..." se puede escribir tambien como "GRANT ALL..."
Podemos obtener la lista de permisos de las tablas asi:
select * from all_tab_privs_made;

Notas

Los permisos del sistema pueden ser:
   CREATE SESSION - Permite conectar a la base de datos
   UNLIMITED TABLESPACE  - Uso de espacio ilimitado del tablespace.
   SELECT ANY TABLE - Consultas en tables, views, or mviews en cualquier esquema
   UPDATE ANY TABLE - Actualizar filas en tables and views en cualquier esquema
   INSERT ANY TABLE - Insertar filas en tables and views en cualquier esquema
   Permisos de administrador para CREATE, ALTER o DROP:
     cluster, context, database, link, dimension, directory, index,
     materialized view, operator, outline, procedure, profile, role,
     rollback segment, sequence, session, synonym, table, tablespace,
     trigger, type, user, view. 
Los roles predefindos son:
   SYSDBA, SYSOPER, OSDBA, OSOPER, EXP_FULL_DATABASE, IMP_FULL_DATABASE
   SELECT_CATALOG_ROLE,  EXECUTE_CATALOG_ROLE, DELETE_CATALOG_ROLE
   AQ_USER_ROLE, AQ_ADMINISTRATOR_ROLE - manejo de la cola
   SNMPAGENT - Agente inteligente.
   RECOVERY_CATALOG_OWNER - rman
   HS_ADMIN_ROLE - servicios heterogeneos
mas cualquier rol de usuario que halla disponible Los roles CONNECT, RESOURCE y DBA ya no deben usarse (aunque estan soportados).
Es posible asignar varios Object_Privs en un solo comando GRANT.
GRANT SELECT (empno), UPDATE (sal) ON pepe.tabla TO miusuario
Permisos del rol SYSDBA:
    CREATE DATABASE
    CREATE SPFILE
    STARTUP and SHUTDOWN
    ALTER DATABASE: open, mount, back up, or change character set
    ARCHIVELOG and RECOVERY
    Includes the RESTRICTED SESSION privilege
Permisos del rol SYSOPER:
    CREATE SPFILE
    STARTUP and SHUTDOWN
    ALTER DATABASE: open, mount, back up
    ARCHIVELOG and RECOVERY
    Includes the RESTRICTED SESSION privilege
Cada tipo de objeto tiene su propio conjunto de permisos:
Tables: select, insert, update, delete, alter, debug, flashback, on commit refresh, query rewrite, references, all
Views: select, insert, update, delete, under, references, flashback, debug
Sequence: alter, select
Packeges, Procedures, Functions (Java classes, sources...): execute, debug
Materialized Views: delete, flashback, insert, select, update
Directories: read, write
Libraries:execute
User defined types: execute, debug, under
Operators: execute
Indextypes: execute

sábado, 1 de noviembre de 2014

null Sessions en Windows



De Null Session, NetBIOS y otras vulnerabilidades conocidas en sistemas Windows

 
 
 
 
 
 
 
Róger un buen amigo mío auditor de sistemas, me ha enviado un artículo acerca de Null Sessions para que como especialista en seguridad le comentara mi opinión al respecto, pues efectivamente es un tema un poco controversial, les comparto mis reflexiones. 
Muy interesante tu artículo Róger está bastante detallado y muy informativo, le recomiendo a los lectores del blog que antes de continuar descarguen el archivo que me remitió Róger y lo lean, es un poco largo pero vale la pena. Null Sessions o Login Anónimo
En resumen el texto habla de Null Sessions, que es un recurso de NetBIOS (Network Basic Input/Output System) en los sistemas Windows para lograr ciertos tipos de conectividades que permiten unas tantas funcionalidades importantes a nivel de sistema para redes Windows; pero esto plantea ser un agujero de seguridad dejado a propósito por los programadores de Windows para resolver de una manera ligera un problema de compatibilidad hacia atrás entre sistemas Windows Server y Sistemas NT, he aquí el dilema. ¿Porqué es una vulnerabilidad?, porque permite que un usuario sin cuenta pueda establecer una sesión con un equipo Windows y hacer una enumeración de recursos como cuentas de usuarios, grupos, recursos compartidos, políticas de contraseña, etc., aunque esta actividad aparentemente sería incapaz de dañar el sistema operativo el punto sería analizar si es o no una amenaza. 
 
 
  

Análisis de Fundamento

¿Es o no saludable que alguien husmee mi sistema “inocentemente”?, pues a mí no me gustaría ver a ningún extraño asomando por la ventana hacia el interior de mi casa y contabilizando mis enseres domésticos; televisor, equipo de sonido, computadora, etc. ¿A usted le gustaría?, OK, esa es la respuesta para la pregunta de si Null Sessions es o no inocente. ¿Cómo lo declaro yo?, CULPABLE, no quiero que nadie esté husmeando mis sistemas, inocente o no inocentemente. 
 
 
 
 
  

Un poquitín de historia (Aquellos que no aprendieron la historia, están condenados a repetirla.)

  
Suficiente de parábolas, examinemos un poco de materia. Recuerdo los albores de la civilización cuando salió a la venta Windows 95 (de hecho esta historia comienza un poco antes) y aún los más duchos informáticos eran incapaces de conectar en red dos computadoras, simple y sencillamente por su desconocimiento de protocolos como TCP/IP (en aquellos entonces los protocolos de Novell Networks eran los reyes), pero como Billy desde hacía años venía urdiendo su malévolo plan de colocar una PC con Windows en cada hogar del mundo, tuvo la genial idea de empacar con Windows un protocolo llamado NetBIOS, jovencito precoz que media vez le ponías un cable ethernet era capaz de mostrarte las otras PC con sus recursos compartidos, carpetas compartidas, impresoras compartidas, ¡Hasta el nombre de la PC!, imaginen que maravilla…. Y sin configurar el sistema operativo ni un ápice. La maravilla de la tecnología te permitía montar la red en tu oficina o en tu Pyme con solo tener un hub, unos pocos cables y las compu con su respectiva impresora, OK ahora a producir dinero todo el mundo. ¿Qué hacía esto posible? Simple, todos los puertos habidos y por haber venían abiertos por defecto y NetBios enumeraba todos esos recursos, imagínense, más de 65,000 puertos en escucha, el paraíso de los hackers; pero, siempre hay un pero, como ni los chicos buenos estaban muy instruidos tampoco los chicos malos estaban muy instruidos, así que quedamos tablas. Windows 95 se comenzó a apoderar de la red y vino Billy y vio que eso era bueno.  
 
Un minuto de silencio para Linux, la fortaleza, con todos y cada uno de sus puertos deshabilitados por defecto, a como debe ser un sistema operativo seguro y robusto; con una ligereza técnica como esa Windows puso el primer pie en la luna.  

Hablemos ya más técnico pues

Máxima de Seguridad 1: A mayor seguridad, menor funcionalidad y facilidad de uso.  
Y los Windows siguieron estando con todos sus puertos abiertos hasta que salió Service Pack 2 para Windows XP (6 de agosto del 2004), en el cual Billy ya incluyó el primer Firewall de Windows, tiempos aún remotos en los que pocos administradores de sistemas sabían qué era un Firewall o para qué servía (aparte de no dejar que algunas aplicaciones trabajaran). Resulta que, este Firewall primitivo (solo podías administrar tráfico entrante, no el saliente) y unas cuantas directivas de grupo (políticas de Windows) eran ya suficientes para combatir al hacker más taimado, pues estos hackers sí habían aprendido la lección y comenzaron a explotar la falta de seguridad de Windows, armados los administradores con estos primitivos pertrechos y un poco de conocimiento de puertos necesarios por sistema podías aplicar otra máxima de seguridad.  
 
Máxima de Seguridad 2: Aplicar donde se pueda, el principio del menor privilegio posible.  
Convirtamos entonces a nuestro Windows en un Linux (Ahggg! Pero no importa, Windows ya le llevaba entonces 10 años de ventaja a Linux en el mercado) y cerremos todos los puertos de red, esto bloqueará Null Session y cualesquier otra vulnerabilidad de red, ahora comencemos a preguntarnos qué puertos deberían de estar abiertos y a quien se le deberían presentar:  
¿Estoy en un dominio?, Si: abrir puertos 137, 138, 445, etc., ¿A toda la red?, No: a las direcciones IP de los controladores de dominio, no más.  
¿Comparto recursos?….mmm… carpetas compartidas; mala idea, erradíquenlas. Emmm…¿Impresoras compartidas? ¡Diablos!, ¿Es que la empresa para la cual trabajas no tiene para una impresora de red?, No le pongamos 3 patas al gato.  
¿Tengo aplicaciones de administración de equipos?, inventario de PC, anti-virus,s administración de parches, monitoreo, etc. Todas estas aplicaciones por lo general trabajan con un puerto específico, averígüenlo y lo abren… ¿Para toda la red?, Otra vez no, solamente para la IP de sus servidores de administración.  
Al final las estaciones de trabajo NO son servidores, por lo tanto NO deben de tener puertos abiertos para otras estaciones de trabajo, deben de ser ciegas, sordas y mudas, solo deben de intercambiar conectividad con los servidores, en puertos puntuales y en direcciones IP puntuales, punto.  
Los hackers ahora saben más, pero también los administradores de red saben más; y tenemos más herramientas, tenemos IPSec, IPv6, VPN, SSL y toda una miríada de utilidades que nos permiten asegurar nuestros recursos. A partir de Windows XP Service Pack 3 muchas de esas herramientas de enumeración no pueden vulnerar Windows, ya ni se diga de Windows Vista y Windows 7 con firewalls poderosos y compatibilidad nativa con todos los protocolos de seguridad listados anteriormente, es cuestión de estudiar estas funcionalidades a fondo y sacarles el máximo provecho antes que la tecnología decaiga a como lo hizo NetBios, en su tiempo fue una maravilla pero ahora ingratamente es catalogado como un agujero de seguridad, cuando lo que ha ocurrido es que simplemente se ha tornado obsoleto.