3. Seguridad declarativa en WildFly (JAAS)

Desde el punto de vista del programador, no hay grandes diferencias a la hora de desarrollar y desplegar una aplicación en WildFly, GlassFish u otro servidor de aplicaciones, pero es desde la perspectiva del administrador desde donde cada producto muestra una forma diferente de operar. Desde este punto de vista hemos querido cubrir los aspectos más generales del uso de WildFly. A partir de ahora nos centraremos en la seguridad.

En esta sesión hablaremos sobre seguridad en declarativa en WildFly y en la siguiente hablaremos de seguridad en la capa de transporte

3.1. Implementación de la seguridad declarativa en WildFly

A estas alturas ya tenemos una idea general sobre seguridad declarativa, pero como repaso vamos a revisar una serie de conceptos que enlazan lo que ya hemos visto con algunos elementos nuevos:

Usuarios, grupos y roles

Son los elementos básicos a la hora de definir la seguridad de una aplicación Web y que ya hemos utilizado a lo largo del curso. En el caso concreto de WildFly, grupo y rol se tratan como un mismo concepto, como veremos más adelante.

Políticas de seguridad

Son asociaciones entre recursos de WildFly y usuarios o roles. Es decir nos permiten definir exactamente quién puede acceder a un determinado recurso y qué operaciones puede hacer con él.

Dominios de seguridad (Security Domains)

Son las configuraciones de autenticación, autorización, mapeo de seguridad y auditoría propias del servidor de aplicaciones. Implementan la especificación JAAS (Java Authentication and Authorization Service) de seguridad declarativa.

Security Realms

Los Realm son los almacenes de usuarios, password y roles de las interfaces de administración del servidor (puntos de entrada) tanto desde el exterior como internamente en el propio servidor. Son componentes sobre los que se sustentan los security domain. De inicio WildFly cuenta con dos Security Realm:

  • ManagementRealm: que sirve para securizar el acceso a las herramientas de administración (Autenticación)

  • ApplicationRealm: que se utiliza para controlar el acceso a las aplicaciones desplegadas (Autenticación y Autorización).

La configuración del Realm de administración es la siguiente:

 <security-realm name="ManagementRealm">
	<authentication>
		<local default-user="$local" skip-group-loading="true"/>
		<properties path="mgmt-users.properties" relative-to="jboss.server.config.dir"/>
	</authentication>
	<authorization map-groups-to-roles="false">
		<properties path="mgmt-groups.properties" relative-to="jboss.server.config.dir"/>
	</authorization>
 </security-realm>

El Realm distingue entre accesos desde la máquina local y accesos remotos. Para los primeros no se requiere password, por lo que la herramienta CLI ejecutada en local se conecta directamente, como ya vimos en la primera sesión. En el caso de utilizar CLI contra una instancia remota o acceder a través de la Consola Web sí que se nos pedirá usuario/password.

Los ficheros indicados mgmt-users.properties y mgmt-groups.properties contendrán los usuarios y grupos a los que pertenecen.

El concepto de grupo sí existe para el ManagementRealm ya que se pueden definir grupos de usuarios y posteriormente asociarlos con roles de administración RBAC (que veremos al final de la sesión).

El Realm de aplicaciones tiene una configuración muy parecida:

<security-realm name="ApplicationRealm">
	<authentication>
		<local default-user="$local" allowed-users="*" skip-group-loading="true"/>
		<properties path="application-users.properties" relative-to="jboss.server.config.dir"/>
	</authentication>
	<authorization>
		<properties path="application-roles.properties" relative-to="jboss.server.config.dir"/>
	</authorization>
</security-realm>

También admite un usuario local de tipo invitado $local y codifica la información de usuarios en ficheros locales. En este caso sí está habilitado el mapeo entre usuarios y roles y se define un fichero específico para ello.

Los Security Realm se pueden utilizar tanto en conexiones provenientes del exterior como en conexiones internas. El ejemplo típico de esto último es el subsistema Remoting utilizado para acceder al contenedor de EJB’s, que por defecto está vinculado al Realm de aplicaciones:

<subsystem xmlns="urn:jboss:domain:remoting:2.0">
 <endpoint worker="default"/>
 <http-connector name="http-remoting-connector" connector-ref="default" security-realm="ApplicationRealm"/>
</subsystem>

3.1.1. Security Domain y Login Modules

Los Security Domain definen las políticas de autenticación y autorización del servidor de aplicaciones. Un security domain configura uno o varios login modules que implementan estas políticas. La configuración por defecto es la siguiente:

        <subsystem xmlns="urn:jboss:domain:security:1.2">
            <security-domains>
                <security-domain name="other" cache-type="default">
                    <authentication>
                        <login-module code="Remoting" flag="optional">
                            <module-option name="password-stacking" value="useFirstPass"/>
                        </login-module>
                        <login-module code="RealmDirect" flag="required">
                            <module-option name="password-stacking" value="useFirstPass"/>
                        </login-module>
                    </authentication>
                </security-domain>
                <security-domain name="jboss-web-policy" cache-type="default">
                    <authorization>
                        <policy-module code="Delegating" flag="required"/>
                    </authorization>
                </security-domain>
                <security-domain name="jboss-ejb-policy" cache-type="default">
                    <authorization>
                        <policy-module code="Delegating" flag="required"/>
                    </authorization>
                </security-domain>
            </security-domains>
        </subsystem>

Además del Dominio other tenemos los dominios jboss-ejb-policy y jboss-web-policy que componen los módulos de autorización predefinidos, pero el security domain que nos interesa es el denominado other.

Other es el security domain por defecto en la instalación, preparado para trabajar con el Application Realm y en él podemos identificar dos login modules distintos:

Remoting

Utilizado internamente cuando las peticiones de autenticación se reciben a través del protocolo Remoting (habitualmente llamadas a un EJB).

RealmDirect

Utilizado en el resto de peticiones (por ejemplo, al acceder a una aplicación Web). Este módulo tiene la particularidad delegar en un Realm la tarea de autenticación, que por defecto será el ApplicationRealm.

jboss security
El Realm que utilizará RealmDirect se puede especificar mediante el module-option realm.

Por defecto, los login modules se ejecutarán en el orden en el que se hayan definido. Adicionalmente existe un parámetro denominado flag en cada login module, que nos permitirá definir cómo tratar cada resultado parcial.

Puede tener los siguientes valores:

Required

El usuario debe validarse con éxito necesariamente. Independientemente del resultado intentará validarse con el resto de login modules.

Requisite

El usuario debe validarse con éxito necesariamente. Una vez validado, intentará validarse con el resto de login modules. Las siguientes validaciones podrán fallar pero el usuario seguirá autenticado (excepto si tienen el atributo de requerido). Si falla la validación, termina el proceso de autenticación.

Sufficient

El usuario intentará validarse, si falla lo intentará con el resto de login modules, pero si es autenticado, la validación termina en ese punto.

Optional

El usuario intentará validarse, aunque no necesariamente tiene porqué tener éxito. Si todos los login modules están configurados como optional, necesariamente tendrá que validarse con al menos uno de ellos.

El módulo RealmDirect tiene una única opción, el password-stacking que debe ser utilizado con el valor useFirstPass si se utilizan varios login modules.

En esta sesión trabajaremos con tres login modules:

  • RealmDirect almacena usuarios y roles en ficheros. Estos ficheros son los definidos dentro del ApplicationRealm.

  • Database almacena usuarios y roles en una base de datos relacional.

  • LDAP almacena usuarios y roles en un servidor LDAP como OpenLDAP.

La lista completa de login modules la podéis encontrar en esta página: https://docs.jboss.org/author/display/AS71/Security+subsystem+configuration

3.1.2. Activación de la auditoria de seguridad

En la fase de construcción resulta muy útil habilitar la auditoría de seguridad antes de comenzar a trabajar con seguridad declarativa. El log normal de Wildfly no suele proporcionar información significativa cuando intentamos acceder a una aplicación securizada y por la causa que sea el servidor no considera válidas nuestras credenciales.

La forma de hacerlo en WildFly es un tanto enrevesada pues hay que añadir la siguiente información al subsistema de logging:

<subsystem xmlns="urn:jboss:domain:logging:2.0">
			...
            <periodic-rotating-file-handler name="AUDIT" autoflush="true">
                <level name="TRACE"/>
                <formatter>
                    <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
                </formatter>
                <file relative-to="jboss.server.log.dir" path="audit.log"/>
                <suffix value=".yyyy-MM-dd"/>
                <append value="true"/>
            </periodic-rotating-file-handler>
            <logger category="org.jboss.security">
                <level name="TRACE"/>
                <handlers>
                    <handler name="AUDIT"/>
                </handlers>
            </logger>
			...

Con este cambio crearemos un nuevo fichero de log, denominado audit.log en la carpeta de logs del servidor con toda la información de la negociación de la seguridad declarativa.

3.2. Administración de usuarios y roless con RealmDirect

La forma de dar de alta o editar usuarios ya la conocemos y es a través del script add-user.sh especificando el realm de Aplicaciones. Desde este script se permite asociar un usuario a uno o varios grupos (roles):

What groups do you want this user to belong to? (Please enter a comma separated list, or leave blank for none)[  ]: usuarios
add-user.sh da de alta los usuarios indistintamente en la modalidad de standalone y domain.

Los usuarios se almacenarán con el siguiente formato:

username=HEX(MD5(username ':' realm ':' password))

Ejemplo:

experto=579f4faae456fd4b742f89e35fa935e2
admin=c22052286cd5d72239a90fe193737253

Los roles se especificarán como texto plano en el fichero application-roles.properties:

experto=Users
admin=Administrators

3.2.1. Realm Personalizado

Como comentamos, RealmDirect utiliza el ApplicationRealm como Realm por defecto a la hora de autenticar usuarios en ficheros. Es perfectamente posible crear un nuevo Realm con una ubicación de ficheros distinta y especificar dicho Realm como el Realm a utilizar por Realm Direct en nuestro security domain. De esta forma podríamos tener separados los usuarios de nuestra aplicación, del común del servidor. La limitación es que el script add-user no da facilidades para trabajar con distintos Realm por lo que es necesario dar de alta manualmente los usuarios (encriptación(hash) de password incluida).

3.2.2. Configuración de un login module basado en BD

Vamos a agregar al dominio other el login module Database, apoyado en una base de datos externa siguiendo los siguientes pasos:

  1. Crear una base de datos MySQL , denominada "seguridad" con las siguientes tablas

    CREATE TABLE USERS (
        principal_id VARCHAR(64) primary key,
    	password VARCHAR(64));
    ;
    
    CREATE TABLE ROLES (
        principal_id VARCHAR(64) primary key,
    	user_role VARCHAR(64),
    ;
    
    ALTER TABLE ROLES
       ADD CONSTRAINT FK1_PRINCIPLES
       FOREIGN KEY ( principal_id)
       REFERENCES USERS (principal_id)
       ON DELETE CASCADE
    ;
  2. Definir un usuario específico para la conexión a la BD seguridad: usuSeg, clave usuSeg. Esto lo podéis hacer desde la herramienta MySQL Workbench que tenéis en Linux.

  3. Crear un origen de datos en WildFly, de nombre java:jboss/datasources/seguridad, que acceda a la BD que acabamos de crear.

  4. Crear un nuevo security domain que utilice el login module Database:

# Crear un nuevo security domain con seguridad basada en base de datos
batch

connect

# Configure the security domain
/subsystem=security/security-domain=seguridad/:add(cache-type=default)
/subsystem=security/security-domain=seguridad/authentication=classic:add(login-modules=[{"code"=>"Database", "flag"=>"required", "module-options"=>[("dsJndiName"=>"java:jboss/datasources/seguridad"),("principalsQuery"=>"SELECT PASSWORD FROM USERS WHERE principal_id = ?"), ("rolesQuery"=>"SELECT user_role, 'Roles' FROM ROLES where principal_id = ?")]}])

# Run the batch commands
run-batch

# Reload the server configuration
:reload
Grupos
WildFly no introduce el concepto de grupos de usuarios pero la implementación del Login Module Database es muy flexible, por lo que se puede modelar una tabla de grupos, asociar usuarios a grupos y permitir asociar roles a los grupos. Después de esto, bastaría con modificar las queries de recuperación de roles.

3.2.3. Protección de las password

Nuevamente WildFly no nos da un sistema directo para proteger las constraseñas pero si nos permite especificar un mecanismo de encriptación/hash y encargarnos nosotros mismos de su gestión. Concretamente hay que añadir las siguientes opciones al login module:

<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="hashAlgorithm" value="MD5"/>
<module-option name="hashEncoding" value="hex"/>

Con estas opciones se especifica el algoritmo para calcular el hash a partir de la contraseña, así como la forma de convertir la cadena binaria resultande en una representación en formato de texto (base64).

En la siguiente dirección tenéis una utilidad para calcular estos hash, es importante que el hash generado se introduzca en minúsculas porque la validación es case sensitive: http://md5-hash-online.waraxe.us/

Aplicación Web de Ejemplo

Vamos a construir una sencilla aplicación Web que aproveche la configuración de seguridad que hemos preparado hasta ahora. Esta aplicación Web contará con un único servlet que mostrará la lista de usuarios de la BD seguridad.

Para ello definiremos un servlet y lo protegeremos de tal modo que sólo los usuarios y administradores puedan acceder a él. Utilizaremos la autenticación Basic para simplificar.

Lo construiremos en los siguientes pasos:

  1. Configurar el nuevo dominio "seguridad" en IntelliJ. Crear un nuevo proyecto Web, mediante Maven.

  2. Crear un servlet que responda a la ruta /listado, y que devuelva la consulta:

    @WebServlet("/protegido/ConsultaServlet")
    @ServletSecurity(@HttpConstraint(rolesAllowed = { "rol_usuario","rol_administrador" }))
    public class ConsultaServlet extends HttpServlet {
    
        @Resource(mappedName = "java:jboss/datasources/seguridad")
        DataSource segDS;
    
        protected void processRequest(HttpServletRequest request,
                                      HttpServletResponse response)
                throws ServletException, IOException {
    
            String query = "SELECT * FROM USERS";
            Connection conn = null;
            Statement stmt;
    
            response.setContentType("text/html;charset=UTF-8");
    
            PrintWriter out = response.getWriter();
            try {
    
                conn = segDS.getConnection();
                stmt = conn.createStatement();
    
    
                out.println("<html>");
                out.println("<head>");
                out.println("<title>Servlet listado</title>");
                out.println("</head>");
                out.println("<body>");
    
                out.println("Lista de usuarios:<BR/>");
    
                ResultSet rs = stmt.executeQuery(query);
                while(rs.next())
                {
                    out.println(rs.getString("principal_id")+"/"+rs.getString("password")+"<br/>");
                }
    
                out.println("</body>");
                out.println("</html>");
            } catch (Exception e) {
                out.println(e.getMessage());
    
            } finally {
                try {
                    out.close();
                    if(conn!=null)
                        conn.close();
                } catch (SQLException ex) {
                    Logger.getLogger(ConsultaServlet.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
  3. Configurar los descriptores de despliegue. El archivo web.xml tendrá un aspecto parecido a este:

     <session-config>
      <session-timeout>30</session-timeout>
      </session-config>
     <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
     <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>Mi dominio de seguridad</realm-name>
      </login-config>
     <security-role>
      <description />
      <role-name>rol_usuario</role-name>
      </security-role>
     <security-role>
      <description />
      <role-name>rol_administrador</role-name>
      </security-role>
      </web-app>
    WildFly en su versión 8.10 da algunos problemas a la hora de combinar diferentes tipos de restricciones de integridad sobre un mismo recurso. Como recomendación intentad siempre que sea posible, no declarar más de una restricción sobre un mismo recurso de la aplicación.
  4. Añadiremos el descriptor específico de WildFly jboss-web.xml, en la carpeta WEB-INF:

<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/schema/jbossas/jboss-web_8_0.xsd"
           version="8.0">

    <context-root>/intranet</context-root>
    <security-domain>
        seguridad
    </security-domain>
</jboss-web>

En el estamos indicando tanto el contexto raiz de la aplicación como el security domain contra el que vamos a autenticarnos.

3.2.4. Integración con un servidor LDAP Externo

LDAP ("Lightweight Directory Acces Protocol") es un protocolo de tipo cliente-servidor para acceder a un servicio de directorio.

Cada entrada en el directorio LDAP describe un objeto (por ejemplo: una persona, un recurso de red, una organización) y tiene un único identificador llamado Nombre Distinguido (DN, Distinguished Name). La entrada consiste de una colección de atributos (por ejemplo una persona podría tener apellido, organización, e-mail). Para encontrar las entradas hay que navegar a través del Árbol de Información de Directorio (DIT, Directory Information Tree). En la raíz del árbol se encuentra "el mundo", el cual esta subdividido en el siguiente nivel en países, y en el siguiente en organizaciones. Dentro de las organizaciones se almacenan información de gente, recursos, etc.

ldap1

Es habitual en empresas de cierto tamaño el tener un servidor donde se almacena la información corporativa de directorio. Los servidores de aplicaciones suelen integrar componentes que permiten acceder a la información de usuarios y roles que resida en dicho servidor LDAP.

En nuestra máquina virtual, podemos simular este directorio corporativo instalando OpenLDAP y cargando un directorio de pruebas. Estos serán los pasos a seguir:

  1. Instalar el servidor SLDAPd ejecutando los comandos:

    sudo apt-get update
    sudo apt-get -y install slapd ldap-utils
  2. Configuración básica del directorio:

    sudo dpkg-reconfigure slapd
    Preguntas Respuestas

    Omit OpenLDAP server configuration

    No

    DNS domain name

    ua.es

    Organization name

    jtech

    Administrator password

    expertojavajs

    Database backend to use

    HDB

    Do you want the database to be purged

    yes

    Move old database

    yes

    Allow LDAPv2 protocol

    no

  3. Configurar el nuevo dominio LDAP mediante un script en lenguaje LDIF:

    #grupo de usuarios
    dn: ou=users,dc=ua,dc=es
    objectClass: organizationalUnit
    ou: users
    
    #grupo de roles
    dn: ou=roles,dc=ua,dc=es
    objectClass: organizationalUnit
    ou: roles
    
    #alumno1
    dn: uid=alu1,ou=users,dc=ua,dc=es
    objectclass: top
    objectclass: uidObject
    objectClass: inetOrgPerson
    objectclass: person
    uid: alu1
    cn: Cuenta de alu1
    sn: alu1
    userPassword: alu1
    mail: alu1@ua.es
    
    #alumno2
    dn: uid=alu2,ou=users,dc=ua,dc=es
    objectclass: top
    objectclass: uidObject
    objectClass: inetOrgPerson
    objectclass: person
    uid: alu2
    cn: Cuenta de alu2
    sn: alu2
    userPassword: alu2
    mail: alu2@ua.es
    
    #profesor1
    dn: uid=prof1,ou=users,dc=ua,dc=es
    objectclass: top
    objectclass: uidObject
    objectClass: inetOrgPerson
    objectclass: person
    uid: prof1
    cn: Cuenta de prof1
    sn: prof1
    userPassword: prof1
    mail: prof1@ua.es
    
    #definir rol_usuario y miembros
    dn: cn=rol_usuario,ou=roles,dc=ua,dc=es
    objectclass: top
    objectclass: groupOfNames
    cn: rol_usuario
    description: grupo de alumnos
    member: uid=alu1,ou=users,dc=ua,dc=es
    member: uid=alu2,ou=users,dc=ua,dc=es
    
    #definir rol_administrador y miembros
    dn: cn=rol_administrador,ou=roles,dc=ua,dc=es
    objectclass: top
    objectclass: groupOfNames
    cn: rol_administrador
    description: grupo de profesores
    member: uid=prof1,ou=users,dc=ua,dc=es

    No vamos a entrar en detalle sobre cómo se configura un servidor LDAP, pero como podéis ver en la configuración, hay una clara jerarquía de objetos. Partiendo del dominio jtech, se crea un usuario administrador y dos unidades organizativas. Dentro de esas dos unidades organizativas (usuarios y grupos) crearemos a su vez un usuario (de login usuario) y un grupo denominado usuarios.

Si os fijáis, al final se indica que el usuario "usuario" pertenece al grupo "usuarios". Cada objeto que hemos comentado se localiza por su dn y en su nombre va arrastrando toda la estructura del directorio.

Para cargar esta configuración en nuestro LDAP, debéis ejecutar lo siguiente:

sudo ldapadd -x -D cn=admin,dc=ua,dc=es -W -f directorio.ldif

Para comprobar que todo ha ido bien, podéis consultar el directorio mediante el comando ldapsearch:

sudo ldapsearch -x -b 'dc=ua,dc=es' '(objectclass=*)'

(El asterisco es un comodín, si queréis podéis probar a sustituirlo por cualquier valor de "objectclass" que veáis en la configuración).

JXplorer

Otra opción para trabajar sobre el directorio es utilizar un cliente LDAP, como por ejemplo, JXplorer. Una vez el directorio tenga la configuración básica, podemos conectarnos a él, indicando el dn de la organización y el usuario/password del administrador. Se nos mostrará gráficamente la composición del directorio y se nos permitirá añadir/modificar/borrar elementos del mismo:

ldap2
ldap3

3.2.5. Login module LdapExtended

Una vez configurado nuestro directorio LDAP, debemos añadir y configurar el login module específico para Ldap en nuestro security domain:

<login-module code="LdapExtended" flag="required" >
	<module-option name="java.naming.factory.initial" value="com.sun.jndi.ldap.LdapCtxFactory"/>
	<module-option name="java.naming.provider.url" value="ldap://localhost:389"/>
	<module-option name="java.naming.security.authentication" value="simple"/>
	<module-option name="bindDN" value="cn=admin,dc=ua,dc=es"/>
	<module-option name="bindCredential" value="expertojavajs"/>
	<module-option name="baseCtxDN" value="ou=users,dc=ua,dc=es"/>
	<module-option name="baseFilter" value="(uid={0})" />

	<module-option name="rolesCtxDN" value="ou=roles,dc=ua,dc=es" />
	<module-option name="roleFilter" value="(member={1})" />
	<module-option name="roleAttributeID" value="cn" />

	<module-option name="searchScope" value="ONELEVEL_SCOPE" />
    <module-option name="allowEmptyPasswords" value="true" />
</login-module>
Cuidado con los espacios en blanco después de los valores de cada propiedad que configuréis tanto en los ficheros LDIF como en los valores de las propiedades. Os ahorraréis bastantes quebraderos de cabeza…​

3.3. Role Based Access Control en interfaces de administración

Por último, comentar que a partir de WildFly 8, se introduce también el control de autorización en tareas administrativas. Hasta ahora en JBoss cualquier usuario con acceso al ManagementRealm se consideraba super usuario y podía realizar cualquier tarea de administración. Desde esta nueva versión es posible establecer un control mas preciso de lo que un usuario puede hacer y lo que no, habilitando el control RBAC:

<management>

        <access-control provider="simple"> <!-- cambiar por rbac-->
            <role-mapping>
                <role name="SuperUser">
                    <include>
                        <user name="$local"/>
						<user alias="experto" name="experto" /> <!-- Añadir al menos un usuario como Superusuario después del cambio -->
                    </include>
                </role>
            </role-mapping>
        </access-control>

    </management>

En la sección de roles se muestra un único rol (superusuario), pero tras habilitar el mecanismo de roles tenemos a disposición nuestra los siguientes roles:

Role Permissions

Monitor

El más restrictivo. Solo permisos de consulta de la información en tiempo de ejecución. No permite la consulta de recursos, datos o información de log.

Operator

Los permisos de Monitor y además puede parar/arrancar instancias, activar/desactivar colas JMS y liberar conexiones de base de datos.

Maintainer

Los permisos del Operator y además puede modificar la configuración: desplegar nuevas aplicaciones y recursos.

Deployer

Los permisos de Maintainer pero restringidos al despliegue de aplicaciones.

Administrator

Los permisos de Maintainer pero además permite ver y modificar datos sensibles tales como sistemas de seguridad. No tiene acceso al sistema de auditoria de administración (audit loggin system).

Auditor

Los permisos del monitor más la posibilidad de poder consultar/modificar el audit logging system).

Super User

Tiene todos los permisos, y es el equivalente al usuario administrador de versiones anteriores.

La administración de la asignación de roles a usuarios y/o grupos está integrada en la consola Web, en contraposición al alta de usuarios, que se sigue haciendo por script.

En el caso de querer asociar un grupo de usuarios (mgmt-groups.properties) a un rol de administración, se añadiría de la siguiente forma:

<role name="Deployer">
	<include>
		<group alias="group-lead-devs" name="lead-developers"/>
	</include>
</role>

3.5. Ejercicios de seguridad declarativa en WildFly

Nuestro siguiente proyecto será poner en marcha una sencilla intranet para nuestra organización donde se muestren las noticias más importantes del día.

Trabajaréis sobre el proyecto Maven apli-intranet. Esta aplicación web contempla dos tipos de acciones:

  • Consulta de noticias del día, abierta a cualquier empleado (autenticado) de la empresa, mediante el servlet ConsultaServlet.

  • Alta de nuevas noticias, únicamente habilitada para los usuarios administradores de la intranet con el servlet NuevoMensajeServlet.

El contexto raíz de la aplicación debe ser /intranet y a este nivel se encuentra la página y el servlet que implementan la consulta. El JSP y Servlet de alta de noticias se encuentran en /intranet/admin para que podamos establecer restricciones de seguridad diferenciadas.

La información relativa a nuestra aplicación se almacenará en la BD seguridad que hemos presentado en la teoría y que crearemos con el script incluido en las plantillas. Para acceder a la base de datos, crearemos un origen de datos al que denominaremos java:jboss/datasources/seguridad.

La tabla donde almacenaremos las noticias tiene el siguiente esquema:

CREATE TABLE  `noticias` (
  `fecha` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `noticia` varchar(1024) DEFAULT NULL
)

Para poner en marcha este proyecto definiremos la seguridad en tres fases separadas, en las que iremos sumando distintos orígenes de datos de información de autenticación (ficheros, base de datos, LDAP) para que trabajen de forma conjunta.

3.5.1. Configuración, despliegue y alta de usuarios en WildFly (0.6 puntos)

En este ejercicio configuraremos el modelo de seguridad general que queremos para nuestra aplicación. Para ello crearemos un nuevo security domain, al que llamaremos seguridad-domain. Funcionará de forma similar al security domain Other pero almacenando la información de usuarios y roles en ficheros específicos.

Será necesario crear un nuevo realm, de nombre IntranetRealm y que almacenará la información de usuarios en los siguientes ficheros:

  • intranet-users.properties

  • intranet-roles.properties

Una vez definido el modelo de seguridad general, definiremos los siguientes roles:

  • usuarios, que contendrán al conjunto de usuarios de la empresa y tendrán el rol: rol_usuario.

  • administradores, que serán aquellos usuarios que tengan permiso para dar de alta nuevas noticias en la aplicación, poseerán el rol: rol_administrador.

Como el desarrollo de la aplicación lo llevan a cabo dos programadores, daremos de alta cada uno de ello con un rol distinto y los incluiremos como usuarios del IntranetRealm de WildFly:

  • programador1 (clave programador1), que tendrá asociado el rol usuario.

  • programador2 (clave programador2), asociado al rol administrador.

Por último, habrá que modificar el código fuente de la aplicación para que:

  • Se utilice el nuevo security domain y especificar el contexto raíz /intranet.

  • Definir los roles autorizados para ejecutar los distintos servlets mediante anotaciones:

    • /ConsultaServlet: roles usuario y administrador:

    • /admin/NuevoMensajeServlet: sólo podrán ejecutarlo los usuarios administradores

Debéis comprobar que el usuario "programador1" sólo puede ver las noticias del día, mientras que el usuario "programador2" también puede añadir nuevas noticias a la base de datos.

3.5.2. Gestión de usuarios en Base de datos (0.3 puntos)

En nuestra empresa hay un número variable de empleados externos. Estos empleados no pertenecen a ningún directorio corporativo pero se mantienen en una base de datos. El objetivo de este ejercicio es añadir al security domain un login module que trabaje con usuarios y grupos mantenidos en la BD seguridad.

Debeis configurar login module como se explica en teoría, configurando el parámetro flag de los login module de modo que un usuario se reconozca como autenticado cuando sea válido para al menos un login module (basado en ficheros o en BD).

Para comprobar que todo está en orden, daréis de alta los siguientes usuarios:

  • consultor1 (clave consultor1), asociado al rol usuario.

  • consultor2 (clave consultor2), asociado al rol administrador.

Es importante almacenar las contraseñas codificadas por tanto hay que configurar el login module de modo que utilice MD5 en la validación. Asimismo tenéis que comprobar que los usuarios programador1 y programador2 siguen trabajando con normalidad!!

3.5.3. Seguridad integrada con LDAP corporativo (0.3 puntos)

En esta última fase, enlazaremos el directorio corporativo de la empresa con el security domain de WildFly, de modo que un usuario se definirá en el directorio, y en función del rol asociado, tendrá acceso parcial o completo a la aplicación.

Debéis seguir los pasos descritos en teoría y ejecutar el script LDIF que se adjuntan como plantilla. Este script creará automáticamente los siguientes usuarios:
  • alu1 (clave alu1) asociado al rol usuario.

  • alu2 (clave alu2) asociado al rol usuario.

  • prof1 (clave prof1) asociado al rol administrador.

Podéis utilizar la herramienta JXplorer para comprobar que los usuarios se han creado correctamente, y si tenéis problemas para autenticar algún usuario, recordad que tenéis que habilitar la auditoría de seguridad, para que os dé más detalle de lo que ocurre.

El resultado de las tres fases es un security domain que obtiene información sobre los usuarios de múltiples orígenes y permite establecer reglas de seguridad unificadas.

3.5.4. Entrega

En esta sesión debeis entregar el proyecto apli-intranet con las modificaciones requeridas y la configuración de WildFly standalone.xml.