Jun 08

Esto no pretende ser una introducción a “Business Intelligence”, sino solo un resumen practicó de cómo se implementa, y la relación de sus principales componentes, podríamos verlo como una Ficha Resumen (ayuda de memoria).

Business Intelligence, relación Datawarehouse, Datamart, Cubos OLAP, y ETL

Business Intelligence, relación Datawarehouse, Datamart, Cubos OLAP, y ETL

Business Intelligence: conjunto de estrategias y herramientas enfocadas a la administración y creación de conocimiento mediante el análisis de datos existentes en una organización.

Datawarehouse: base de datos especial para toma de decisiones de negocio, bases datos solo lectura, que contiene la relación completa de los principales datos de negocio. En el enfoque bottom –up, Datawarehouse es la unión de todos los Datamart.

Datamart: Datawarehouse especifico a un área de la negocio o de la organización orientada a decisiones de dicha área. Los Datamart se analizan mediante herramientas OLAP.

OLAP: procesamiento analítico en línea, para ello utiliza estructuras multidimensionales llamadas “Cubos OLAP”, permite “jugar” con la información de Negocio, obteniendo distintas vistas (reportes) de la información.

Cubos OLAP: contienen datos resumidos de Datamart u otros tipos de Bases de Datos, en un formato especial para Análisis, son bases de datos multidimensionales. Este tipo de base de datos multidimensional esta optimizada para las consultas query, a diferencia de las bases de datos relacionales que están orientadas a la transaccionalidad (OLTP).

Bajo un producto específico de BI como Pentaho (Opensource), tenemos las siguiente herramientas (http://community.pentaho.com/projects/bi_platform/ ):

  • Servidor Reporting y Análisis OLAP: servidor que permite generar vistas y reportes con información de negocio, además de análisis cubos OLAP; “Pentaho Reporting”.
    http://reporting.pentaho.com/
Jun 04

Es difícil encontrar un buen y completo ejemplo (o tutorial) de cómo validar (autenticar) un usuario mediante LDAP desde una aplicación Java, y es más difícil encontrar un tutorial en español.

En este ejemplo supondremos que el servidor LDAP es OpenDJ (antes OpenDS)

http://www.forgerock.com/opendj.html

Pero este tutorial aplica tanto para Oracle OpenDS como para ForgeRock OpenDJ, porque están basado en los mismos fuentes.

OpenDJ es un “Directory Server” Open Source, que implementa el protocolo LDAP.

Un “Directory Server” es una base de datos “optimizada” que puede guardar todo tipo de información, pero su uso se ha extendido principalmente como Base de Datos de perfilación, y de componentes de dominio.

Un “Directory Server” puede guardar todo tipo de información, maneja índices, filtros y mecanismos de búsqueda muy eficientes, las bases de datos relacionales están basadas en esta tecnología, podríamos decir que un “Directory Server” es equivalente al “Lenguaje C”, y una “Base de Datos Relacional” es equivalente a un lenguaje de alto nivel como “Java” (que se basa en C), en otras palabras si queremos manejar data en tiempo real y con alta carga, una opción adecuada puede ser usar Directory Server.

La información en LDAP se guarda en forma de árbol (tree) con subniveles “ilimitados” parecido a una estructura XML, maneja conceptos de atributos y clases de objetos (objectClass). Veremos una estructura básica de usuarios-organización:

Suponemos que la estructura anterior se implementó usando el “Control Panel” de OpenDJ

Existen algunos conceptos y  atributos básicos de LDAP

  • DN: “Distingished Name”, corresponde al path completo de atributos que referencian únicamente a un registro LDAP, en el ejemplo del árbol para el usuario “cn=juan perez” su DN es:

cn=juan perez,ou=depto_informatica,dc=soaagenda,dc=com

Haciendo una equivalencia con bases de datos relacionales, son los campos     llave con que se identifica únicamente un registro.

  • cn: “common name” corresponde al nombre común del elemento para un usuario su nombre y apellido.
  • ou: “organizational unit” nombre de un departamento de la organización, puede identificar una empresa, una sucursal, un departamento, o un área de la Organización. Tambien se usa para identificar un grupo de personas como “clientes”.
  • dc: “domain component” sire para identificar el dominio, se usar un par por ejemplo para www.soaagenda.com se define con “dc=soagenda, dc=com”.

Otros atributos de un usuario:

  • sn: “surname” es el apellido.
  • givenName: es el nombre de pila
  • uid: “user id” una identificación única más orientado a sistema, mientras que “common name” (cn) está más orientado a personas (nombre común), por ejemplo un uid puede ser un código numerico.
  • userPassword: password del usuario esta encriptada en SHA.

Para nuestro ejemplo:

  • cn= juan perez
  • uid=jperez
  • givenName=Juan
  • sn=Perez
  • mail=juan.perez@soaagenda.com
  • userPassword= claveY
  • telephoneNumber=5550000

Bueno, a lo que vinimos, este es el código de ejemplo para validar un usuario y obtener sus datos.

package com.soaagenda;

import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

/**
 *
 * @author soaagenda.com
 */
public class UtilsLDAP {
   
    private String INITCTX = "com.sun.jndi.ldap.LdapCtxFactory";
    private String HOSTLDAP = "ldap://localhost:389";
    private String BASE = "DC=soaagenda,DC=com";

    public boolean validaUsuario(String userDN, String pass) {           
        Hashtable env = new Hashtable();
        if (pass.compareTo("") == 0 || userDN.compareTo("") == 0)
            return false;
        
        env.put(Context.INITIAL_CONTEXT_FACTORY,INITCTX);
        env.put(Context.PROVIDER_URL, HOSTLDAP);
        env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, new String(userDN));  
        env.put(Context.SECURITY_CREDENTIALS,new String(pass));
        
        DirContext ctx=null;
        try {
            ctx = new InitialDirContext(env);
        } catch (NamingException ex) {
            Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }

        try {
            if (ctx!=null) ctx.close();
        } catch (NamingException ex) {
            Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }        
        return true;   
    }    
    
   public String obtieneUsuario(String adminDN, String adminPass, String uidBuscar) {           
        Hashtable env = new Hashtable();
 
        env.put(Context.INITIAL_CONTEXT_FACTORY, INITCTX);  
        env.put(Context.PROVIDER_URL, HOSTLDAP);   
        env.put(Context.SECURITY_AUTHENTICATION, "simple");  
        env.put(Context.REFERRAL, "follow" );
        env.put(Context.SECURITY_PRINCIPAL, new String(adminDN));  
        env.put(Context.SECURITY_CREDENTIALS,new String(adminPass));  

       DirContext dctx=null;
       try {
            dctx = new InitialDirContext(env);

        
            String base = BASE;
            String filter = "(&(objectClass=organizationalPerson)(uid="+uidBuscar+"))";

            SearchControls controls = new SearchControls();

            String []strReturningAttr = {"member","uid","sn","cn","mail","userPassword"};

            controls.setReturningAttributes(strReturningAttr);
            controls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            NamingEnumeration answer= null;
            try {
                answer = dctx.search(base, filter, controls);
            } catch (NamingException ex) {
                Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
                ex.printStackTrace();
                return "error";
            }

            while (answer.hasMoreElements()) {
                SearchResult sr;
                try {
                    sr = (SearchResult)answer.next();
                } catch (NamingException ex) {
                    Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ex);
                    ex.printStackTrace();
                return "error";
                }

                Attributes attrs = sr.getAttributes();

                Attribute attr = attrs.get("mail");
                String mailX="";
                if (attr!=null) try {
                    mailX=(String) attr.get();
                } catch (NamingException ignoreX) {
                    Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ignoreX);
                    ignoreX.printStackTrace();
                }

                attr = attrs.get("userPassword");
                Object passW=null;
                if (attr!=null) try {
                    passW= attr.get();
                } catch (NamingException ignoreX) {
                    Logger.getLogger(UtilsLDAP.class.getName()).log(Level.SEVERE, null, ignoreX);
                    ignoreX.printStackTrace();
                }
                
                return sr.getName()+"\nmail="+mailX+"\npassw="+passW.toString();    

            }//while

        }catch (NamingException e) {
            e.printStackTrace();
            return "error";
        }finally{
            try{
                if (dctx!=null) dctx.close();
            }catch (Exception ignore){}
        }        

        return "usuario no existe";   
    }
    
    public static void main(String[] argv) {
        UtilsLDAP utilX = new UtilsLDAP();

        if (utilX.validaUsuario("cn=Directory Manager","primeras")) 
               System.out.println("USUARIO ADMIN VALIDO");
        else
               System.out.println("USUARIO o PASSWORD ERRONEO PARA ADMIN");

        if (utilX.validaUsuario("cn=juan perez,ou=depto_informatica,dc=soaagenda,dc=com","claveY")) 
               System.out.println("USUARIO VALIDO");
        else
               System.out.println("USUARIO o PASSWORD ERRONEO");
        
        String usuarioX=  utilX.obtieneUsuario("cn=Directory Manager","primeras","jperez"); 
        System.out.println(usuarioX);
    }    
    
}

Lo principal en esta aplicación es que define al principio el servidor LDAP:

private String HOSTLDAP = “ldap://localhost:389″;

private String BASE = “DC=soaagenda,DC=com”;

Y la función de validación se basa en el DN y la password (userPassword)

validaUsuario(“cn=juan perez,ou=depto_informatica,dc=soaagenda,dc=com”,”claveY”)

La aplicación retorna el siguiente resultado (System Out)

USUARIO ADMIN VALIDO

USUARIO VALIDO

cn=juan perez,ou=depto_informatica

mail=juan.perez@soaagenda.com

passw=[B@174cc1f

May 30

Uno de los puntos que viene poco explicado en OpenDS (Directory Server o LDAP Server) es como instalar la aplicación como servicio, en este artículo lo vamos a explicar.

Este articulo supone que se bajó  OpenDS (download)

http://opends.java.net/public/downloads_index.html

Y se instaló siguiendo el tutorial:

http://java.net/projects/opends/pages/2_2_InstallationGuide

El cual obviamente no explica como subirlo como servicio Linux. Vamos a suponer que OpenDS quedo instalado en “/opt/OpenDS-2.2.1/bin/” para el resto de este tutorial.

Se supone que con este comando se genera el script del servicio…

./create-rc-script -f /etc/init.d/opends

Pero el “script” generado tiene algunos problemas, por ejemplo si lo queremos registrar con “chkconfig”:

chkconfig –add opends

Da el siguiente error:

service opends does not support chkconfig

Esto debido a que no viene indicado la descripción del servicio, que normalmente se define como comentario:

# chkconfig: 2345 20 80
# description: OpenDS Directory and LDAP Server
# processname: opends

Y otro problema es que el script no maneja la opción “status” que sirve para que el sistema operativo cuando trate de levantar el servicio sepa si este realmente está “arriba”.

Aquí está el script completo y corregido, este lo deben copiar en “/etc/init.d/opends” (pisando el que ya generamos).

#!/bin/sh
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License").  You may not use this file except in compliance
# with the License.
#
# You can obtain a copy of the license at
# https://OpenDS.dev.java.net/OpenDS.LICENSE.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at
# trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
# add the following below this CDDL HEADER, with the fields enclosed
# by brackets "[]" replaced with your own identifying information:
#      Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
# chkconfig: 2345 20 80
# description: OpenDS Diarectory and LDAP Server
# processname: opends

# Set the path to the OpenDS instance to manage
INSTALL_ROOT="/opt/OpenDS-2.2.1"
export INSTALL_ROOT

# Specify the path to the Java installation to use
OPENDS_JAVA_HOME="/usr/java/jdk1.6.0_31"
export OPENDS_JAVA_HOME

cd ${INSTALL_ROOT}

# Determine what action should be performed on the server
case "${1}" in
start)
"${INSTALL_ROOT}/bin/start-ds" --quiet
exit ${?}
;;
stop)
"${INSTALL_ROOT}/bin/stop-ds" --quiet
exit ${?}
;;
restart)
"${INSTALL_ROOT}/bin/stop-ds" --restart --quiet
exit ${?}
;;
status)
"${INSTALL_ROOT}/bin/status" -D "cn=Directory Manager" -w primeras -X -s
exit ${?}
;;
*)
echo "Usage:  $0 { start | stop | restart | status}"
exit 1
;;
esac
exit 0

Ahora si podemos registrar el servicio sin problema

chkconfig –add opends

Reiniciamos el sistema Linux, y luego lo probamos con la siguiente comando OpenDS (situándonos en el path “/opt/OpenDS-2.2.1/bin/”)

./status -D “cn=Directory Manager” -w password -X -s

Donde “password” debe corresponder a la clave del administrador del “Directory Server”, que se indicó cuando se instaló OpenDS. Este comando debe retornar

“Server Run Status: Started….”

También podemos probarlo usando la consola de OpenDS

./control-panel

Apr 26

El Enterprise Service Bus WSO2, viene por defecto con una base de datos H2 interna (embedded), que la usa principalmente para el manejo del Registry (backup o registro de la configuración del ESB).

La base de datos H2 (http://www.h2database.com) es una base de datos ligera que viene con su propia consola de administración Web(H2 Console Server), que permite administrar la base de datos, y se accede en el puerto 8082 (por defecto). ejemplo:

http://localhost:8082/login.jsp

En “WSO2 Carbon” esta consola viene inhabilitada, hablamos WSO2 Carbon en forma generica porque aplica a la mayoria de las aplicaciones WSO2 incluido el ESB.

Para Habilitarla se debe “descomentar” la siguiente sección en el archivo de configuración “carbon.xml” que normalmente se encuentra en “\opt\wso2esb\repository\conf”:

    <h2databaseconfiguration>
        <property name="web" />
        <property name="webPort">8082</property>
        <property name="webAllowOthers" />
        <property name="tcp" />
        <property name="tcpPort">9092</property>
        <property name="tcpAllowOthers" />
        <property name="pg" />
        <property name="pgPort">5435</property>
        <property name="pgAllowOthers" />
        <property name="baseDir">${carbon.home}</property>
    </h2databaseconfiguration>

Pero al reiniciar el servidor WSO2 puede dra el siguiente error:

ERROR – DatabaseUtil Database Error – Tabla “UM_DIALECT” no encontrada, Table “UM_DIALECT” not found

Esto porque durante la instalación por defecto no se crea la tabla “UM_DIALECT”, luego hay que forzar su creación iniciando el servidor con la opción “-DSETUP”:

sh wso2server.sh -Dsetup (Linux)

wso2server.bat -Dsetup (Windows)

Esto se requiere hacer solo una vez, el resto de las subidas dels ervidor pueden ser con el comando que estemos usando, o como servicio de Linux o Windows.

Luego se puede entrar en la consola Web (http://localhost:8082/login.jsp)

login h2 console wso2

Los datos para conectarse son (basados en configuración por defecto wso2):

  • Server Setting:  Generic H2 (Embedded)
  • Setting Name: xxx
  • Driver class: org.h2.Driver
  • JDBC URL: jdbc:h2:repository/database/WSO2CARBON_DB
  • User Name: wso2carbon
  • Password: wso2carbon

Otras referencias

Utilizar Oracle como base de datos WSO2

http://docs.wso2.org/display/Governance411/Setting+up+with+Oracle

Tutorial rapido de H2

http://wso2.org/blog/sumedha/3734

Jan 23

“Reverse Ajax” visto desde “afuera”, visto desde el punto de vista de un “usuario”, es el mecanismo que permite que la información en una aplicación Web se “refresqué” automáticamente sin necesidad que lo solicite explícitamente (ejemplo; sin apretar un botón de “actualizar”), y donde no se tenga que volver a cargar la página completa (Ajax). Un ejemplo de esto sería una aplicación de la Bolsa de Comercio donde se muestran los valores de las acciones, los cuales se van actualizando automáticamente a medida que cambia el valor, y no cada vez que el usuario presiona un botón.

Una forma de “simular” esto, es que la pagina (cliente web) tenga un ciclo de consulta recurrente cada X segundos (un loop), el problema es que estriamos llenando de solicitudes (peticiones, o request) el servidor, lo que es poco eficiente.

“Reverse Ajax” corresponde a enviar información desde un servidor a los distintos clientes (Web) sin la necesidad explicita de una solicitud (request) por parte del cliente, este es el concepto de “empujar” (push) la información. Normalmente la información se entrega (push) de acuerdo a un evento que sucede en el servidor, por ejemplo actualización del valor de una acción.

Para lograr esto, los clientes Web (Browser) deben quedar esperando (escuchando) la información que pueda venir del servidor, y el servidor distribuye la información entre los distintos clientes “activos”.

“Reverse Ajax” tiene varias versiones e implementaciones, la técnica estándar es “Long pooling” usando el objeto Request de Ajax, a esta técnica también se le llama Comet. Y las implementaciones más usadas son los frameworks:

• Jetty Continuation:
• CometD
• Grizzly

Las dos primeras son independientes de Servidor de Aplicaciones, trabajan tanto en Jetty, Tomcat, GlassFish, o WAS, pero requieren que el servidor maneje “Servlet 3.0”. La tercera es propietaria de Glassfish, pero cumple los estándares, es decir puede atender a cualquier cliente Comet, y esta optimizada para este servidor.

Aquí hay un ejemplo completo de “reverse Ajax” con Grizzly (Glassfish)

http://docs.oracle.com/cd/E19776-01/820-4496/6nfv5l568/index.html

Este es un tutorial de Jetty y DWR

http://www.ibm.com/developerworks/java/library/j-jettydwr/

Implementacion usando servlets

http://www.ibm.com/developerworks/web/library/wa-cometjava/

Excelente introducción a COMET y revision de implementacion con CometD

http://www.ibm.com/developerworks/web/library/wa-reverseajax1/index.html?ca=drs-

Dec 28

El concepto de “avisos clasificados qrcode”, o “avisos QRCode”,  (“avisosQRcode” de aquí en adelante), corresponde a la publicación de avisos que tienen asociado un QRCode (Quick Response Code). Esto aplica a avisos clasificados, avisos económicos, o cualquier tipo de publicación de avisos.

El nuevo concepto avisosQRcode y un sitio que lo implementa se define (entre otras) mediante las siguientes características principales:

  • Generación QRCode asociado al aviso: cada aviso tiene asociado un QRCode, y este es generado automáticamente cuando se publica el aviso.

aviso clasificado codigo qr (qrcode)

El QRcode apunta al aviso directamente, y además puede contener la información del aviso (codificada la información que se publica).

  • Letrero QRCode o Impresión Aviso QRCode: una de las características más importantes, es que esta nueva idea cambia el concepto del letrero de un aviso clasificado. En los medios tradicionales de publicación de avisos, el letrero dice en grandes letras “Se Vende” y luego aparece algún dato de contacto (número telefónico o email) y del producto.

Letrero aviso clasificado tradicional

.

Estos carteles (tradicionales) generalmente se colocan en la ventana de la propiedad que se vende, o se pegan en el vehículo que se vende, de forma de publicitar la venta o arriendo.

El cartel o letrero QRCode de avisos clasificados es distinto, importa principalmente la imagen del QRCode, debe ser lo más grande posible, de forma que pueda ser escaneado de cierta distancia, por ejemplo desde otro auto cuando se está parado en un semáforo, también contempla los datos del aviso por si alguien no puede hacer el escaneo del código, pero no son estrictamente necesarios, ya que el QRCode da acceso a toda la información del aviso.

Este es el ejemplo de un cartel QRCode de avisos clasificados (cuya conceptualización también es parte de este “registro intelectual”):

Letrero Aviso Clasificado Codigo QR (QRCode) miniavisos.cl

(imagen) Letrero “aviso clasificado qrcode”

El “letrero QRCode” debe indicar un título como “Se Vende” o “Se Arrienda”, para el ejemplo dice “miniAvisos.cl” (lo cual induce a que es un aviso clasificado), además debe presentar el código QRCode ocupando la mayor proporción del letrero, e indicar finalmente los datos del aviso. El orden de esto componentes recomendado es el que se muestra, pero puede ser otro y el concepto “original” sigue siendo el mismo.

Este “letrero” lo genera la aplicación de “avisosQRCode” para su impresión, luego generalmente está asociada a la funcionalidad “imprimir aviso”.

Al colocar un letrero de estas características en la ventana de lo que se vende o arrienda, se identifica inmediatamente que se trata de un “aviso clasificado Qrcode”.

  • Acceso Directo al Aviso Mediante Dispositivos Móviles: cuando se escanea el código QRCode mediante un dispositivo móvil, este lleva directamente al aviso publicado en el sitio web (ejemplo: http://adspip.com/miniavisos/arriendo-departamento-a-pasos-de-renaca/), de esta forma la persona que escanea el QRCode tiene inmediatamente acceso al aviso, pudiendo guardarlo en su dispositivo móvil. Con esto se evita anotar los datos del aviso, o datos de contacto del mismo, haciendo más efectiva la publicación, y posterior transacción.

Para escanear un “codigo QR” se necesita que el dispositivo móvil tenga una aplicación de escaneo, estas pueden venir preinstaladas en el móvil, o se pueden descargar de forma gratuita:

descargar QRCode scanner o Lector de Codigo QR

Referencias:

  • Sitio Oficial para publicar Avisos Clasificados Gratis con Codigo QR o QRCode

miniAvisos.cl

Nov 22

Para calcular la cantidad de días entre dos fechas, no existe una solución en las librerías comunes de Java (java.util.date). Una solución es el siguiente código:

public long periodo(Date fecha1, Date fecha2){
if (fecha1==null || fecha2==null){
return 0;
}
long milli1=fecha1.getTime();
long milli2=fecha2.getTime();
long diffMillis= milli2 - milli1;
if (diffMillis&lt;0) diffMillis= -diffMillis;
long diffDays = diffMillis/(24*60*60*1000);

return diffDays;
}

Pero existen libreras que realizan estas funcionalidades y otras de forma bastante completa  como

  • Date4J

http://www.date4j.net/

  • Joda-Time

http://joda-time.sourceforge.net/

Nov 19

Esta es una vulnaberabilidad de un sitio Web que permite que se  pueda inyectar codigo en una pagina, como inyectra codigo Javascript.

Por ejemplo supongamos hay un sitio Web que tiene un formulario (form) que solicita el login del usuario, el cual se valida y si no es correcto se devuelve una pagina Web indicando “el nombre de usuario XXX es incorrecto”, donde “XXX” corresponde al dato ingresado (nombre usuario) en el formulario.

Si uno ingresa “DIEGO” como nombre de usuario y este no es válido, entonces se va a desplegar:

el nombre de usuario DIEGO es incorrecto


Lo que esta bien, pero el problema es cuando se coloca este texto

“<script>alert(19700328)</script>”

como nombre de usuario, y la pagina muestra una alert Javascript con el numero “19700328”.

En este caso, esa pagina es vulnerable en “Cross Site Scripting”.

Este es el codigo de la pagina formulario del ejemplo:

< %@ page contentType="text/html; charset=utf-8" language="java" import="java.sql.*" errorPage="" %>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>form cross scripting</title>
</head>
<body>
<form id="formID" name="formID" method="post" action="paginaVulnerable.jsp">
<label>Usuario:
<input name="usuarioID" type="text" id="usuarioID" size="30" />
</label>
<br />
<label>
Clave:
<input type="password" name="passwordID" id="passwordID" />
</label>
<input type="submit" name="ok" id="ok" value="OK" />
</form>
</body>
</html>

Y este es el código de la pagina que es “vulnerable”, es decir, se le puede inyectar javascript:

< %@ page contentType="text/html; charset=utf-8" language="java" import="java.sql.*" errorPage="" %>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>vulnerable</title>
</head>
<body>
<strong>Error<br />
</strong>el nombre de usuario < %=request.getParameter("usuarioID")%> es incorrecto
</body>
</html>

La solución es validar a nivel de servidor, de la siguiente forma:

  • Primero validar a nivel del tipo de dato, por ejemplo validar que el campo sea un email válido.
  • Segundo validar que no vengan caracteres “peligrosos”

<> (mayor, menor)

| (pipe)

& (ampersand)

; (punto coma)

$ (signo moneda)

% (porcentaje)

‘ (comilla simple)

” (comilla doble)

\’ (backslash-comilla)

\” (backslash-doble comilla)

() (parentesis)

+ (signo mas)

CR (retorno carro, ASCII 0x0d)

LF (salto linea, ASCII 0x0a)

, (coma simple)

@ (arroba)

Luego al devolver o usar el campo, se debe

  • Primero, usar la secuencia de escape adecuada, por ejemplo para las paginas Web (Html) podemos usar “escapeHtml”( http://commons.apache.org/lang/download_lang.cgi ), con lo cual el browser no lo interpreta como un comando Javascript o comando Html.
  • Luego,  si efectivamente el valor entregado es “extraño”, por ejemplo se detecta que tiene palabras reservadas Javascript ni siquiera devolverlo en una pagina, y registrarlo en el log de la aplicación.
< %@ page contentType="text/html; charset=utf-8" language="java" import="java.sql.*" errorPage="" %>
< %@ page import = "org.apache.commons.lang.StringEscapeUtils"%>
< !DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>vulnerable</title>
</head>
<body>
<strong>Error<br />
</strong>el nombre de usuario "
< %=StringEscapeUtils.escapeHtml(request.getParameter("usuarioID"))%>
" es incorrecto
</body>
</html>

Lo bueno que para encontrar este tipo de problemas existen herramientas que revisan un sitio y entregan un reporte con toas las vulnerabilidades como IBM AppScan (http://www-01.ibm.com/software/awdtools/appscan/)

Aug 13

La ruta que se ha definido en Arquitectura de Sistemas para el desarrollo de soluciones o sistemas informáticos es SOA (Arquitectura Orientada a Servicios), la cual esta basada en la implementación de Servicios de Negocio, esto es; bloques funcionales de negocio que se pueden integrar, y compartir en distintas aplicaciones. La principal tecnología para implementar servicios SOA es WebServices, y es la que se recomienda, se promueve y exige, pero hay que tener cuidado, porque fácilmente se puede cometer errores, sino se asumen los siguientes principios:: 

·         Un Webservice no necesariamente es un Servicio SOA. 

·         Un Servicio SOA no necesariamente tiene que ser implementado como WebService. 

Para que un WebService se considere un Servicio SOA, debe cumplir con los estándares SOA, a grandes rasgos: debe corresponder a una funcionalidad del Negocio bien acotada (self cointained), independiente de la implementación tecnológica e independiente de los sistemas operacionales que lo soportan (loose coupling), y además debe poder ser compartido y reutilizado por otros procesos o sistemas (reuse). Por otro lado, un servicio SOA podría ser implementado con otras tecnologías, como HttpService, Mensajería, Ajax (DWR), etc, pero nuevamente para ser considerado como tal, debe cumplir los estándares SOA. 

SOA es una tecnología madura, y respaldada por los principales expertos y empresas, por ejemplo Gartner dentro de su HypeCycle (diagrama de madurez) ya el 2009 lo tiene entrando al nivel de plena productividad (plateau of productivity). (img1) 

Además Gartner la tiene dentro de las tecnologías Top Ten en la industria de Seguros (ref. “Gartner Outlines Top 10 Technologies to Impact Property and Casualty Insurance” – Harris Ferrante  - Marzo 2010).  

IBM se refiere a SOA como “la plataforma que alinea el Negocio con Tecnología” (IBM Smart SOA – Enero 2010, http://www-01.ibm.com/software/solutions/soa/smartsoa/), y ha desarrollado toda una metodología y set de herramientas para apoyar SOA.  

Oracle indica “SOA se ha movido de la sobreespectativa (hype) a una completa aceptación como estrategia de Tecnología (TI) para entregar soluciones de Negocio” (Oracle SOA Governance Solution -2009, http://www.oracle.com/technologies/soa/docs/soa-governance-datasheet.pdf). 

¿Y porque se debe implementar SOA usando WebServices?, en términos simples, porque es el estándar de facto, Webservices es una tecnología que opera en .Net y Java, que la mayoría de los motores de servicios contempla (bases de datos, ESB, ETL, etc), que las herramientas de diseño, desarrollo, y testing soportan, y que las grandes aplicaciones también manejan (CRM, ERP, SAP, SalesForce, etc.). Gartner de hecho tiene los webservices situados en “plena productividad” para Arquitectura de Aplicaciones  (ver “Hype Cycle for Application Architecture, 2009“, http://www.gartner.com/DisplayDocument?id=1077812).  

Los servicios SOA sirven para integrar sistemas, para construir procesos de negocio (orquestación de servicios), pero principalmente sirven para implementar aplicaciones Web. IBM lo ha promovido en el desarrollo de aplicaciones Web, en combinación con frameworks como Struts, Spring, lo ha promovido para el desarrollo de aplicaciones web “rich” (“Build rich Java Web applications with Apache Wink and Ajax“ – Febrero 2010) , y para el desarrollo  de aplicaciones Web dinámicas (“Build RESTful Web services and dynamic Web applications with the multi-tier architecture” –Junio 2009). Oracle lo contempla en su Arquitectura de aplicaciones; Oracle ADF. 

  Arquitectura Orientada a Servicios

Pero como toda tecnología, los WebServices pueden ser mal implementados, si no se siguen los estándares y buenas prácticas, que existen para el desarrollo de Servicios. Uno de los problemas más comunes es pretender que toda funcionalidad de un sistema se puede convertir en un servicio (WebService), y la verdad es que el enfoque es otro, las funcionalidades de Negocio, que pueden involucrar más de un sistema, son las que se deben convertir en Servicios. 

Se han mencionado buenas prácticas y antipatrones para el desarrollo de servicios, las buenas prácticas apuntan a como se deben hacer las cosas, y los antipatrones apuntan a mostrar en que problemas no debemos caer, ejemplos: ·         Servicio se nombra para maximizar consumo.Erróneo: insertarRegistroCliente()Correcto: crearNuevoCliente() 

·         Servicio tienen parámetros abultados (coarse grained)

Erróneo : crearNuevoCliente (rut, nombre, apellidos, email, fono, direccion)

Correcto: crearNuevoCliente (objetoCliente) 

·         Servicio encapsula detalles de implementación.

Erróneo : crearNuevoClientePsoft (schemaOracle, registroTablaCliente )

Correcto: crearNuevoCliente (objetoCliente) 

·         AntiPatrón, Servicio Parlanchines (Chatty Services)

Erróneo: consultaUF()

Correcto: (NO implementar ese tipo funciones como servicios) 

·         IBM SOA Antipatternshttp://www.ibm.com/developerworks/webservices/library/ws-antipatterns/ 

·         IBM SOA realization, Service design principleshttp://www-128.ibm.com/developerworks/webservices/library/ws-soa-design/ 

·         SOA Anti-Patterns: How Not to Do Service-Oriented Architecturehttp://www.oracle.com/technology/architect/entarch/pdf/oea_soa_antipatterns.pdf ·        

·         Best Practices for Web services: Web services performance considerationshttp://www.ibm.com/developerworks/webservices/library/ws-best9/index.html 

¿Pero solo basta con conocer los estándares y buenas prácticas para no equivocar el camino en la implementación de servicios y para lograr los beneficios que promete SOA?;  la verdad es que NO, se necesita más que eso, se pueden saber los patrones de diseño SOA, pero aun no interiorizarlos, o no poder lograrlo con tecnologías especificas como Java, porque solo la experiencia real, y la supervisión continua en la primeras etapas logra que el área de TI adopte de forma adecuada SOA, y aquí es donde entra a jugar otro enfoque; “SOA Governance” , que corresponde a implementar el soporte en procedimientos, metodologías, y herramientas, para lograr un SOA exitoso: 

  • SOA Governance ya no es una opción, es un imperativo, sin esta administración (governance) el retorno de la inversión es mucho menor, y todo proyecto SOA estará en riesgo (ref. “Service Oriented Architecture Craves Governance” – Gartner).
  • De hecho sin él (SOA Governance), muchas iniciativas SOA fallan” (“Oracle SOA Governance Solution” – 2009).

Si la implementación de Servicios SOA falla, entonces es determinante la implementación de un “SOA Governance”, y el primer y mas importante paso en Governance es establecer una área especializada; el “Centro de Excelencia SOA” (SOA COE), que permite enseñar y supervisar la adopción de SOA en una Empresa, un área clave liderada por Arquitectos de Sistemas. 

Aug 13

top ranking sitio Arquitectura de SistemassoaAgenda.com a escalado de forma considerable dentro de los sitios de Articulos de Interes en materias de Arquitectura de Sistemas, Arquitectura Orientada a Servicios (SOA) y Administración de Procesos de Negocio (BPM), estableciendose como referente en estos temas.

En Alexa.org estamos en la posición 200.000 a nivel de españa y 3.500.000 a nivel mundial, superando a muchos sitios de Tecnologia (TI) de varios paises.