lunes, 4 de agosto de 2014

MariNet: mi primer proyecto Web

Era el año 1997 y MariNet nace con el objetivo de "Automatizar los procesos informativos y distribuir información referente a todo el ámbito Naval y Marítimo ...". El proyecto estaba patrocinado por la Asociación de Ingenieros Navales y Oceánicos de España (AINE) y el Colegio Oficial de Ingenieros Navales y Oceánicos.

La web de MariNet tuvo una existencia de dos años y ese es el motivo por el que quiero mostrar un poco en que consistía.

Esta era la página principal:


El menú de la izquierda incluía una lista de enlaces entre los que destacaría:
  • Búsqueda: que te llevaba al buscador de empresas y equipos del que hablaré mas ampliamente a continuación.
  • Países: que incluía links a las web MariNet de otros países.
La parte central incluía una seria de noticias y eventos importantes.

La zona de links de la derecha incluía una serie de diversos enlaces, como catálogos de equipos, consultas predefinidas del buscador de empresas y equipos y normativa.
Sin duda alguna, el buscador de empresas y equipos se convirtió en la parte mas importante de MariNet.

El buscador de equipos te permitía realizar la búsqueda mediante formularios o a través de directorios:


Mediante formularios, podían seleccionarse los directorios paso a paso seleccionando los diferentes niveles:




Mediante los directorios se realizaba la misma búsqueda de una forma más directa:





Al final el resultado de la búsqueda de equipos por cualquiera de los dos métodos era similar, una página con un listado de equipos y que incluía un filtro para afinar las características del equipo buscado:


El filtro de características dependía del tipo de equipo seleccionado.

Desde la página anterior podíamos acceder a las características de un equipo en particular:


Y podíamos acceder a la página de la empresa fabricante o proveedora de los equipos seleccionados y que era la misma página resultado del buscador de empresas; de esta forma ambos buscadores quedaban relacionados:


En esta página podíamos ver un resumen de toda la información de dicha empresa que estaba incluida en la base de datos de MariNet: actividades, tipos de equipos, su número y link para consultarlos en el buscador de equipos y la información de contacto.

Los dos buscadores estaban totalmente integrados.

El buscador de empresas también permitía dos tipos de búsqueda:


Mediante un formulario que realizaba una búsqueda simple por nombre:



O mediante navegación en una serie de directorios:



Por ultimo, incluyo algunos ejemplos de páginas que formaban parte de MariNet.

La página de bienvenida:


Páginas de noticias:


La página de comentarios:


Páginas de catálogos de un equipos:


Páginas con normativa:


A nivel técnico, el proyecto se desarrolló en ASP y SQL Server.

Un saludo

lunes, 21 de julio de 2014

VBscript: ejecutar comandos limitando su duración máxima

Cuando utilizamos VBscript para ejecutar comandos de MS-DOS estos se ejecutan en un proceso aparte diferente del proceso del script original. Si el comando ejecutado no termina correctamente es muy probable que su proceso permanezca abierto indefinidamente.

En el caso de scripts de monitorización, que se ejecutan a intervalos regulares, es necesario controlar estos procesos secundarios para así evitar que multiples procesos secundarios no terminen y queden abiertos en el sistema. Este control podemos hacerlo desde el propio script.

El código siguiente es un ejemplo de como realizarlo para el caso de un script que testea una conexión a una base de datos. El comando que se ejecuta es "sqlplus.exe" y queda parado sin terminar porque la linea "exit" del fichero que ejecuta esta comentada. De esta forma simulamos un problema que tendrá que resolver el script:

'-----------------------------------------------------------------------
' Constantes 
'-----------------------------------------------------------------------
Const ORA_SID="XE"
Const ORA_PORT="1521"
Const operuser="sys"
Const operpwd="manager"
'-----------------------------------------------------------------------

On Error Resume Next

IdProceso= ScriptProcessID()

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set WshShell = CreateObject("WScript.Shell")

scriptPath=WshShell.CurrentDirectory

PathFileConexSQL=scriptPath & "\conexion.sql"
PathFileConexLog=scriptPath & "\conexion.log"

If objFSO.FileExists(PathFileConexLog) Then objFSO.DeleteFile(PathFileConexLog)
If objFSO.FileExists(PathFileConexSQL) Then objFSO.DeleteFile(PathFileConexSQL)

Set objPathFileConexSQL = objFSO.CreateTextFile(PathFileConexSQL)
objPathFileConexSQL.WriteLine("spool " & PathFileConexLog & ";")
objPathFileConexSQL.WriteLine("column host_name format A20;")
objPathFileConexSQL.WriteLine("select host_name, instance_name, status from v$instance;")
objPathFileConexSQL.WriteLine("spool off;")
'objPathFileConexSQL.WriteLine("exit;")
objPathFileConexSQL.Close

comando="sqlplus -L """ & operuser & "/" & operpwd & "@" & ORA_SID & " as sysdba"" @" & PathFileConexSQL
WshShell.Run(comando),2,false

wscript.sleep 10000

Set colProcessList=Nothing
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'sqlplus.exe' And ParentProcessId = " & IdProceso)

If colProcessList.count>0 Then
  For Each objProcess in colProcessList
    MsgBox("Terminando proceso bloqueado ...")
    objProcess.Terminate()
  Next
End If

'If objFSO.FileExists(PathFileConexLog) Then objFSO.DeleteFile(PathFileConexLog)
'If objFSO.FileExists(PathFileConexSQL) Then objFSO.DeleteFile(PathFileConexSQL)

WScript.Quit

'-----------------------------------------------------------------------
' Función obtener el processID de este script
'-----------------------------------------------------------------------
Function ScriptProcessID()

  Set objSWbemServices = GetObject ("WinMgmts:Root\Cimv2")
  Set colProcess = objSWbemServices.ExecQuery("Select * From Win32_Process Where Name='wscript.exe' Or Name='cscript.exe'")

  For Each objProcess In colProcess
    if instr(objProcess.CommandLine,WScript.ScriptFullName)<>0 Then
      ScriptProcessID=objProcess.ProcessID
    End If
  Next

End Function
'-----------------------------------------------------------------------

Lo primero es identificar el ID del proceso de sistema del propio script; esto se hace en la linea:

IdProceso= ScriptProcessID()

La función ScriptProcessID utiliza el ScriptFullName y una consulta WMI para encontrar dicho ID.

Generamos el fichero PathFileConexSQL con la consulta SQL que lanzaremos a la base de datos una vez conectados; dejamos la sentencia "exit" comentada para simular un proceso que no termina:

spool C:\Oracle\conexion.log;
column host_name format A20;
select host_name, instance_name, status from v$instance;
spool off;

Después generamos el comando que vamos a ejecutar, un sqlplus con su cadena de conexión generada a partir de las variables definidas al inicio del script y que una vez conectado a la base de datos ejecutara el fichero anterior:

comando="sqlplus -L """ & operuser & "/" & operpwd & "@" & ORA_SID & " as sysdba"" @" & PathFileConexSQL

Lanzamos el comando y damos un tiempo de espera (10 segundos):

WshShell.Run(comando),2,false
wscript.sleep 10000

Es el momento de confirmar que nuestro comando ha terminado. Lo hacemos mediante una consulta WMI que utiliza el nombre del comando ejecutado, sqlplus.exe, y el ID del proceso padre que lo lanzo, que es el ID de nuestro script obtenido al principio:

Set colProcessList=Nothing
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = 'sqlplus.exe' And ParentProcessId = " & IdProceso)

En caso de que la consulta obtenga algún resultado tenemos que matar dicho proceso, en este ejemplo hemos añadido un mensaje que en un entorno real no tendría sentido incluir:

If colProcessList.count>0 Then
  For Each objProcess in colProcessList
    MsgBox("Terminando proceso bloqueado ...")
    objProcess.Terminate()
  Next
End If

La ejecución del script da este resultado:














Si quitamos el comentario a la linea que hacia el "exit" en la conexión a la base de datos el script funciona perfectamente sin ningún problema:

objPathFileConexSQL.WriteLine("exit;")

Un saludo

miércoles, 2 de julio de 2014

Como trabajar con parámetros tipo Array entre Java y Oracle.

Imaginemos el caso en que para crear un objeto Java necesitamos leer varios registros de una tabla de una base de datos Oracle y queremos hacerlo con una sola llamada a un procedimiento almacenado PL/SQL. Necesitamos poder trabajar con parámetros tipo Array entre Java y Oracle.

Por ejemplo, una clase usuario que aparte de atributos normales incluye dos atributos múltiples de tipo lista de objetos de otra clase servicio:

ArrayList <servicio> servicios = new ArrayList<servicio>();
ArrayList <servicio> intereses = new ArrayList<servicio>();

Tendremos que leer de la base de datos la tabla usuarios y las tablas necesarias para obtener los servicios e intereses de dicho usuario.

Creación de objetos y procedimiento almacenado en Oracle

Necesitamos un objeto tipo que tenga la misma estructura que el objeto servicio:

create or replace TYPE TYP_SERVICIO AS
    OBJECT (SRV_ID NUMBER, SRV_NOMBRE VARCHAR2(40))

Ahora necesitamos un objeto tipo lista que sea una lista del anterior y que utilizaremos como parámetro de salida del procedimiento almacenado:

create or replace TYPE TYP_LST_SERVICIOS_2 AS TABLE OF TYP_SERVICIO;

Los objetos anteriores los utilizamos tanto para los servicios de usuario como para sus intereses porque tienen la misma estructura y, en realidad, los datos vienen de la misma tabla, pero eso no viene al caso. Si no fuese así tendríamos que haber creado otro objeto tipo y lista adicional.

Creamos el procedimiento almacenado en el que realizamos las tres consultas que necesitamos y que requiere de un solo parámetro de entrada, el ID del usuario:

PROCEDURE PRC_USR_GET_DATA(
    P_USR_ID IN USUARIOS.USR_ID%TYPE,
    P_USR_NICK OUT USUARIOS.USR_NICK%TYPE,
    P_USR_NOMBRE OUT USUARIOS.USR_NOMBRE%TYPE,
    P_USR_APELLIDOS OUT USUARIOS.USR_APELLIDOS%TYPE,
    P_USR_EMAIL OUT USUARIOS.USR_EMAIL%TYPE,
    P_USR_LOC_LAT OUT USUARIOS.USR_LOC_LAT%TYPE,
    P_USR_LOC_LONG OUT USUARIOS.USR_LOC_LONG%TYPE,
    P_USR_SALDO OUT USUARIOS.USR_SALDO%TYPE,
    P_USR_VALORACION OUT USUARIOS.USR_VALORACION%TYPE,
    P_USR_FECALTA OUT VARCHAR2,
    P_USR_LASTCONEX OUT VARCHAR2,
    P_SRV_LIST OUT TYP_LST_SERVICIOS_2,
    P_INT_LIST OUT TYP_LST_SERVICIOS_2,
    P_ERROR OUT VARCHAR2
) AS
V_PRC_NOMBRE BT_LOG.LOG_PROCESO%TYPE := 'PKG_USUARIOS.PRC_USR_GET_DATA';
BEGIN
    SELECT USR_NICK, USR_NOMBRE, USR_APELLIDOS, USR_EMAIL,
        USR_LOC_LAT, USR_LOC_LONG, USR_SALDO, USR_VALORACION,
        TO_CHAR(USR_FEC_ALTA, 'DD Month YYYY'),
        TO_CHAR(USR_LASTCONEX, 'DD Month YYYY HH24:MI')
    INTO P_USR_NICK, P_USR_NOMBRE, P_USR_APELLIDOS, P_USR_EMAIL,    
        P_USR_LOC_LAT, P_USR_LOC_LONG, P_USR_SALDO,
        P_USR_VALORACION, P_USR_FECALTA, P_USR_LASTCONEX
    FROM USUARIOS WHERE USR_ID=P_USR_ID;
    SELECT TYP_SERVICIO(S.SRV_ID, initcap(S.SRV_NOMBRE)) bulk collect
        INTO P_INT_LIST
        FROM USR_INT UI LEFT JOIN SERVICIOS S ON S.SRV_ID=UI.SRV_ID
        WHERE UI.USR_ID=P_USR_ID;
    SELECT TYP_SERVICIO(S.SRV_ID, initcap(S.SRV_NOMBRE)) bulk collect
        INTO P_SRV_LIST
        FROM USR_SRV US LEFT JOIN SERVICIOS S ON S.SRV_ID=US.SRV_ID
        WHERE US.USR_ID=P_USR_ID;
    RETURN;
    EXCEPTION WHEN OTHERS THEN
        PKG_LOG.PRC_LOG_WRITE(P_USR_ID, V_PRC_NOMBRE, SQLCODE,
            SUBSTR(SQLERRM,0,200), P_ERROR);
    RETURN;
END PRC_USR_GET_DATA;

Hay que destacar los dos puntos; primero los parámetros de salida que son del mismo tipo lista que creamos anteriormente:

    P_SRV_LIST OUT TYP_LST_SERVICIOS_2,
    P_INT_LIST OUT TYP_LST_SERVICIOS_2,

Y segundo, las consultas para rellenar dichos parámetros de salida:

    SELECT TYP_SERVICIO(S.SRV_ID, initcap(S.SRV_NOMBRE)) bulk collect
        INTO P_SRV_LIST...

Creación de objetos Java

La clase servicio es muy simple, dos atributos y sus métodos getter y setter:

package comun;
public class servicio {
    private int id;
    private String nombre;
    public void setId(int a){ id=a; }
    public int getId(){ return id; }
    public void setNombre(String a){ nombre=a; }
    public String getNombre(){ return nombre; }
}

Es el objeto en el que nos hemos basado para crear el objeto de Oracle TYP_SERVICIO.

La clase usuario tiene un constructor desde el que llama al procedimiento almacenado. Necesita el ID del usuario que queremos crear:

package comun;
import java.sql.*;
import java.util.ArrayList;
import java.sql.Types;
import oracle.sql.STRUCT;
import java.math.BigDecimal;
import comun.BBDD;
import comun.servicio;
public class usuario {
    private int id ;
    private String nick;
    private String nombre;
    private String apellidos;
    private String email;
    private int saldo;
    private double loc_lat;
    private double loc_long;
    private String fec_alta;
    private int valoracion;
    private String ultima_conexion;
    ArrayList <servicio> servicios = new ArrayList<servicio>();
    ArrayList <servicio> intereses = new ArrayList<servicio>();
    private BBDD bd = new BBDD();
    public usuario(int user_id) {
        try{
            Connection conn = bd.conectar();
            bd.conectar();
            CallableStatement cs = conn.prepareCall("{call
                PKG_USUARIOS.PRC_USR_GET_DATA(?,?,?,?,?,?,?,?,?,?,?,?,?,?)}");
            cs.setInt(1, user_id);
            cs.registerOutParameter(2, Types.VARCHAR);
            cs.registerOutParameter(3, Types.VARCHAR);
            cs.registerOutParameter(4, Types.VARCHAR);
            cs.registerOutParameter(5, Types.VARCHAR);
            cs.registerOutParameter(6, Types.DOUBLE);
            cs.registerOutParameter(7, Types.DOUBLE);
            cs.registerOutParameter(8, Types.INTEGER);
            cs.registerOutParameter(9, Types.INTEGER);
            cs.registerOutParameter(10, Types.VARCHAR);
            cs.registerOutParameter(11, Types.VARCHAR);
            cs.registerOutParameter(12, Types.ARRAY, "TYP_LST_SERVICIOS_2");
            cs.registerOutParameter(13, Types.ARRAY, "TYP_LST_SERVICIOS_2");
            cs.registerOutParameter(14, Types.VARCHAR);
            cs.executeUpdate();
            if(cs.getString(14)!=null){
                System.out.println("ERROR: " + cs.getString(14));
            }
            else{
                id=user_id;
                nick=cs.getString(2);
                nombre=cs.getString(3);
                apellidos=cs.getString(4);
                email=cs.getString(5);
                loc_lat=cs.getDouble(6);
                loc_long=cs.getDouble(7);
                saldo=cs.getInt(8);
                valoracion=cs.getInt(9);
                fec_alta=cs.getString(10);
                ultima_conexion=cs.getString(11);
                Array arrS = cs.getArray(12);
                Object[] objArrS = (Object[]) arrS.getArray();
                for(int i=0; i<objArrS.length;i++){
                    STRUCT st = (STRUCT)objArrS[i];
                    servicio service = new servicio();
                    Object[] obj = st.getAttributes();
                    service.setId(((BigDecimal)obj[0]).intValueExact());
                    service.setNombre(String.valueOf(obj[1]));                  
                    servicios.add(service);
                }              
                Array arrI = cs.getArray(13);
                Object[] objArrI = (Object[]) arrI.getArray();
                for(int i=0; i<objArrI.length;i++){
                    STRUCT st = (STRUCT)objArrI[i];
                    servicio service = new servicio();
                    Object[] obj = st.getAttributes();
                    service.setId(((BigDecimal)obj[0]).intValueExact());
                    service.setNombre(String.valueOf(obj[1]));                  
                    intereses.add(service);
                }              
            }          
        }
        catch (Exception ex) {
            System.out.println("ERROR: " + ex.toString());
        }
    }
    public String getNick(){ return nick; }
    public String getNombre(){ return nombre; }
    public String getApellidos(){ return apellidos; }
    public String getEmail(){ return email; }
    public int getSaldo(){ return saldo; }
    public String getFec_alta(){ return fec_alta; }
    public int getValoracion(){ return valoracion; }
    public double getLoc_lat(){ return loc_lat; }
    public double getLoc_long(){ return loc_long; }
    public String getUltima_conexion(){ return ultima_conexion; }  
    public ArrayList <servicio> getServicios(){ return servicios; }
    public ArrayList <servicio> getIntereses(){ return intereses; }
}

Hay que destacar la definición de los parámetros de salida para los servicios e intereses, en los que hay que especificar el tipo de lista definido en Oracle:

    cs.registerOutParameter(12, Types.ARRAY, "TYP_LST_SERVICIOS_2");
    cs.registerOutParameter(13, Types.ARRAY, "TYP_LST_SERVICIOS_2");

y la conversión del Array que se obtiene como salida del procedimiento almacenado en una ArrayList:

    Array arrS = cs.getArray(12);
    Object[] objArrS = (Object[]) arrS.getArray();
    for(int i=0; i<objArrS.length;i++){
        STRUCT st = (STRUCT)objArrS[i];
        servicio service = new servicio();
        Object[] obj = st.getAttributes();
        service.setId(((BigDecimal)obj[0]).intValueExact());
        service.setNombre(String.valueOf(obj[1]));                  
        servicios.add(service);
    }  

Con esto hemos terminado, espero que le sea de utilidad a alguien.

Hasta otra.

miércoles, 25 de junio de 2014

Weblogic 11G: ejemplo de autentificación por formulario contra Directorio Activo de Microsoft

En esta primera entrada lo que voy a hacer es montar una aplicación web con autentificación por formulario contra un Directorio Activo (AD) de Microsoft. Utilizaremos seguridad declarativa para limitar el acceso a los recursos de la aplicación web.

El nivel funcional del dominio será Windows Server 2003, el servidor sobre el que montare la aplicación web será Oracle Weblogic 11G y como entorno de desarrollo utilizaré el IDE Eclipse.

Necesitaremos tener ya instalado y funcionando los tres. La ubicación es indiferente, solo necesitamos tener conexión de un servidor en otro.

El motivo de utilizar el AD en Windows 2003 es que ya lo tengo montado en una maquina virtual aparte; en principio, todo seria igual en un dominio con un nivel funcional mas actual.

Configuración Active Directory

Entramos en nuestro servidor de dominio y en la consola de administración de AD creamos una Unidad Organizativa (OU) para los grupos que utilizare en la gestión de la seguridad de las diferentes aplicaciones:


















Utilizaremos 2 grupos y 3 usuarios para probar los diferentes roles dentro de la aplicación web:
  • grupo APLIC_ACCESO_PPAL: usuarios prueba1 y prueba2
  • grupo APLIC_EXTRANET: usuarios prueba1 y prueba3
Los usuarios los mantendremos en la OU por defecto "Users":


















Configuración Weblogic

En la consola de Weblogic vamos a la ruta Dominios de Seguridad / myrealm / Proveedores, pulsamos "Nuevo" y completamos el nombre del nuevo proveedor de seguridad y elegimos en tipo "Active Directory Authenticator":


















Ahora vamos a configurar este nuevo proveedor:


















Pulsamos en "Volver a Ordenar" y lo ponemos el primero de la lista:


















Tiene que quedar así:


















Ahora seleccionamos el proveedor "CDLLocalAD" y en la pestaña "Común" ponemos como Indicador de Control "SUFFICENT":
















De esta forma bastará que la validación en el AD sea correcta para que el acceso se conceda.

En la pestaña "Proveedor Especifico" pondremos los siguientes valores:
  • Host: 192.168.1.20 (la IP del servidor de dominio de nuestro AD)
  • Puesto: 389 (puerto por defecto LDAP)
  • Principal: Administrator@cdl.local (usuario Administrador del dominio)
  • Credencial: contraseña del usuario anterior en el dominio
  • Confirmar Credencial: confirmación de la contraseña
  • DN Base de Usuario: CN=Users,DC=cdl,DC=local
  • Filtro de Nombre de Usuario: (&(userPrincipalName=%u)(objectclass=user))
  • Atributo de Nombre de Usuario: userPrincipalName
  • DN Base de Grupo: OU=Aplicaciones,DC=cdl,DC=local
Los demás valores los dejamos por defecto. Hay que destacar dos puntos:
  1. El DN Base de Usuario no es OU=Users,DC=cdl,DC=local; asi no funciona porque estamos utilizando el contenedor por defecto de usuarios del AD.
  2. Utilizamos como Atributo de Nombre de Usuario el userPrincipalName y no el "cn", Common Name; podemos elegir el atributo del objeto user del AD que queramos, pero este sera el que luego utilizaremos al hacer login en las aplicaciones.
Llegados a este punto hay que reiniciar el servidor de Weblogic para continuar.

Una vez reiniciado, en la consola de Weblogic vamos a la ruta Dominios de Seguridad / myrealm / Usuarios y Grupos y comprobamos que en las dos pestañas vemos la información de las OUs del AD:

















    Ya tenemos terminada la parte correspondiente a Weblogic y AD; ahora solo tenemos que crear la aplicación y desplegarla.

    Creación de la aplicación web

    Vamos a utilizar la aplicación de ejemplo de los tutoriales de Java, pero incluiré el código por si alguien no dispone de él.

    En Eclipse creamos un nuevo proyecto Web Dinámico llamado "FormBasedApp" con la siguiente estructura y ficheros:


















    El directorio "protected" es el recurso cuyo acceso queremos restringir.

    La pagina por defecto, "welcome.jsp", tendrá solamente un link a una página contenida en el directorio (recurso) que queremos proteger:

    <html>
    <body>
    <center><h1> Welcome Page </h1>
    <h3><font color=maroon><a href="protected/protected.jsp">Access Protected Resource</a></font></h3>
    </center>
    </body>
    </html>

    La página "login.jsp" es el formulario que se presentara para introducir el usuario y la contraseña:

    <html>
    <head>
    <title>FormBased Authentication Demo in WebLogic Sample</title>
    </head>
    <body>
    <center>
    <h2>Please Enter Your UserName & Password (FormBased Auth Example)</h2>
    <form method="GET" action="j_security_check">
    <table border=5%>
    <tr><td>Username:</td><td><input type="text" name="j_username"></td></tr>
    <tr><td>Password:</td><td><input type="password" name="j_password"></td></tr>
    <tr><td colspan=2 align=right><input type=submit value="Submit"></td></tr>
    </table>
    </form>
    </center>
    </body>
    </html>

    No existe un link a login.jsp desde ninguna página; al configurar la seguridad en el fichero web.xml se indica que es este el formulario que se mostrara al intentar acceder al contenido protegido.

    Hay que mantener la nomenclatura de j_security_check, j_username y j_password, marcadas en negrita en el código anterior para que todo funcione, es el estandar de Java el que lo establece así.

    La página "failedlogin.html" solo muestra un mensaje en caso de que la validación haya resultado erronéa:

    <html>
    <body>
    <center> <h1><font color=red>SORRY!!!</font> U are Not Authorized To Access The Resources.
    <BR>
    Please Login With valid Credentials.</h1>
    </center>
    </body>
    </html>

    La pagina "protected,jsp" muestra un mensaje de bienvenida, el nombre de usuario y los roles de la aplicación a los que pertenece dicho usuario:

    <html>
    <head>
    </head>
    <body>
    <center><h1> Protected Page </h1>
    <b><font color=maroon>Congrates!!! Your Login Is Successful...U are able to access the Secure Page.</font></b><BR>
    __________________________***_________________________

    <%String name = request.getUserPrincipal().getName();%>
    <br>Tu nombre es: <%=name %></br>
    <%if (request.isUserInRole("admin")) {%>
    <br>Tu rol es: admin</br>
    <%}%>
    <%if (request.isUserInRole("normal")) {%>
    <br>Tu rol es: normal</br>
    <%}%>

    </center>
    </body>
    </html>

    En el fichero "weblogic.xml" mapeamos los roles de la aplicación con los grupos y usuarios del AD:

    <?xml version="1.0" encoding="UTF-8"?>
    <wls:weblogic-web-app xmlns:wls="http://xmlns.oracle.com/weblogic/weblogic-web-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd http://xmlns.oracle.com/weblogic/weblogic-web-app http://xmlns.oracle.com/weblogic/weblogic-web-app/1.3/weblogic-web-app.xsd">
        <wls:weblogic-version>10.3.6</wls:weblogic-version>
        <wls:context-root>FormBasedApp</wls:context-root>
        <wls:security-role-assignment>
            <wls:role-name>admin</wls:role-name>
            <wls:principal-name>APLIC_ACCESO_PPAL</wls:principal-name>
            <wls:principal-name>Administrator</wls:principal-name>
        </wls:security-role-assignment>
        <wls:security-role-assignment>
            <wls:role-name>normal</wls:role-name>
            <wls:principal-name>APLIC_EXTRANET</wls:principal-name>
            <wls:principal-name>Administrator</wls:principal-name>
        </wls:security-role-assignment>
    </wls:weblogic-web-app>

    En este caso hemos creado dos roles:
    • admin: mapeado al grupo APLIC_ACCESO_PPAL y al usuario Administrator.
    • normal: mapeado al grupo APLIC_EXTRANET y al usuario Administrator.
    Con esta configuración el usuario prueba1 tendrá los dos roles, el usuario prueba2 el rol "admin" y el usuario prueba3 el rol "normal".

    Y por último, en el fichero "web.xml" configuramos la seguridad de nuestra aplicación:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
      <display-name>FormBasedApp</display-name>
      <welcome-file-list>
       <welcome-file>welcome.jsp</welcome-file>
      </welcome-file-list>

    <security-constraint>
    <display-name>Constraint-0</display-name>
    <web-resource-collection>
    <web-resource-name>Constraint-0</web-resource-name>
    <url-pattern>protected/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
    <role-name>admin</role-name>
    <role-name>normal</role-name>
    </auth-constraint>
    <user-data-constraint>
    <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
    </security-constraint>

    <login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
    <form-login-page>/login.jsp</form-login-page>
    <form-error-page>/failedlogin.html</form-error-page>
    </form-login-config>
    </login-config>

     <security-role>
    <role-name>admin</role-name>
     </security-role>
     <security-role>
    <role-name>normal</role-name>
     </security-role>

    </web-app>

    Aquí indicamos la página por defecto (welcome.jsp), los roles de la aplicación (admin y normal), el método de autentificación (FORM), la página que se mostrara al intentar acceder a contenido protegido (login.jsp) y la política de seguridad que en este caso consiste, solamente, en restringir el acceso al directorio "protected".

    Generamos el fichero war en Eclipse y desplegamos la aplicación en Weblogic.

    Prueba de la aplicación

    Accedemos a nuestra aplicación, por ejemplo, desde la pestaña de Testing de la aplicación desplegada en Weblogic:

















    Accedemos al link con el contenido protegido y nos redirige automáticamente al formulario de login:

















    Si introducimos un usuario y/o contraseña errónea o un usuario que no tiene permiso para acceder al recurso protegido nos mostrará la pagina failedlogin.html:

















    Si introducimos un usuario y contraseña válidos nos mostrará la página protegida:

















    Con esto hemos terminado, espero que le sea de utilidad a alguien.

    Hasta otra.

    jueves, 19 de junio de 2014

    Breve presentación personal

    Hola a todos

    He creado este blog con la intención de compartir información y tener un repositorio de notas que considero interesantes o que simplemente me costó encontrar en su momento.

    Empecé a trabajar en el maravilloso mundo de la informática en 1995, en Coritel, como Programador en un proyecto en British Telecom.

    Después, tuve la fortuna de tener una pequeña empresa, AseNet Ingenieros, en la que nos dedicamos sobre todo a impulsar el desarrollo web del sector naval que promovía el Colegio de Ingenieros Navales a través del proyecto Marinet.

    Mas tarde, estuve 3 años en el departamento de Informática Técnica de la E.N. Santa Barbara, diseñando y desarrollando bases de datos documentales para sus departamentos de ingeniería.

    Mi experiencia profesional mas larga fue en Espasa Calpe (Grupo Planeta) donde estuve 8 años participando en varios proyecto de sistemas y desarrollo, especialmente para la Casa del Libro.

    En mi ultimo proyecto, estuve trabajando como Administrador de Sistemas y Bases de Datos Oracle y SQL Server en Mercedes Benz España.

    Mi entorno técnico es Oracle y Microsoft, sobre todo centrado en bases de datos y proyectos de desarrollo, J2EE, C#, VBasic y VBscript.

    Un saludo