En Autentia
trabajamos constantemente en el desarrollo de aplicaciones web
utilizando el framework Struts.
Uno de los aspectos más importantes en el desarrollo de cualquier aplicación web, consiste en dotarla de los mecanismos de validación más
adecuados para garantizar su robustez y fiabilidad. Struts
utiliza el framework Commons
Validator para sus tareas de validación, y hoy os
vamos a mostrar como extender sus mecanismos de validación introduciendo nuevas
reglas junto a las que ya dispone por defecto.
1. Aspectos básicos de validación en
Struts
En este apartado inicial se
procederán a explicar algunos aspectos relativos a la validación en Struts. Esto será necesario para entender, tal como se
explicará más adelante, las acciones necesarias para extender los mecanismos de
validación en Struts.
Para facilitar las acciones
de validación, Struts se apoya en el framework de Apache Jakarta Commons Validator. El
paquete correspondiente del Commons Validator proporciona un framework
simple y extensible para definir métodos y reglas de validación a través de un
archivo xml. También proporciona ayuda para la internacionalización de las
reglas de validación y de los mensajes de error que se precise emitir.
Por defecto, Struts suele emplear el archivo validator–rules.xml para definir los métodos de
validación que utilizará. La definición típica de un método de validación en
este archivo podría tener el siguiente aspecto:
Como puede observarse, en la
etiqueta validator
que define el método de validación se pueden definir diversos campos. En este
caso:
- name :
Nombre asociado a la regla de validación. - classname : Clase que contiene el método con la lógica de
validación correspondiente. - method : Método que contiene la lógica de validación,
situado en la clase especificada en classname. - methodParams : Parámetros de entrada del método indicado en method.
- msg :
Mensaje de error asociado que debe emitir la validación en caso de error.
En este campo se suele especificar una etiqueta asociada a un mensaje en
el fichero MessageResource.properties.
Esta definición corresponde
a la regla de validación required
incluida por defecto con la propia distribución de Struts.
Dicha regla se encarga de comprobar que realmente se han introducido datos en
una entrada. Igualmente, Struts proporciona otras
reglas de validación básicas integradas con el Commons Validator para comprobar tipos de datos,
longitud de datos de entrada, etc.
La definición de estos
métodos en validator–rules.xml se utiliza
para especificar la validación correspondiente a los formularios de la
aplicación construida con Struts. Esta especificación
se suele realizar a través del fichero validation.xml . El aspecto
típico de la especificación básica de la validación asociada a un formulario
podría ser el siguiente:
El significado de los campos
asociados a las etiquetas en esta especificación es el siguiente:
- name :
Nombre del formulario para el que se definirá la validación, cuya bean asociada se encuentra definida en
el fichero de configuración struts–config.xml. - property : Campo del formulario que cuya validación se
desea especificar. Como se acaba de indicar, la información sobre los
campos de un formulario (nombre, tipo, etc) se
especifica igualmente en la definición de la bean asociada a dicho formulario en struts–config.xml. - depends : Especificación de las reglas de validación
asociadas al campo correspondiente. Deben indicarse los nombres de las
reglas que se desean aplicar (pueden indicarse varias, separadas por
comas) definidas en el fichero validator-rules.
Se recuerda que el nombre asociado a cada regla se especifica en el campo name dentro
de cada etiqueta validator
en el fichero validator–rules.xml. - key :
Etiqueta asociada a un mensaje en el fichero MessageResource.properties. Este
mensaje contendrá una cadena de texto con un argumento (nombre, especificación,
etc) que se le pasará al mensaje a mostrar en
caso de error. Los parámetros que muestra un mensaje de error se
especifican en el MessageResource.properties,
en la propia definición de dicho mensaje. Por ejemplo, el mensaje de error
para la regla de validación required podría
especificarse dentro del fichero MessageResource.properties como se muestra a
continuación:
El
{0} indica que se mostrará el mensaje
asociado al campo key
de la primera etiqueta arg
asociada al formulario, en la especificación de
su validación. Volviendo con el ejemplo que se está considerando, si en el
fichero MessageResource.properties
se define form.name=Nombre, el mensaje de error sería la
cadena: Nombre es requerido.
Para utilizar la
configuración de validación (reglas, especificaciones para los formularios, etc) indicada a través de los ficheros validator–rules.xml y validation.xml, debe habilitarse
el plug-in de validación con las rutas a dichos
ficheros. Esto se realiza en el fichero struts–config.xml añadiendo las siguientes líneas, suponiendo
que ambos ficheros cuelgan de /WEB-INF:
Con estas nociones básicas,
se está en disposición de entender la especificación del itinerario básico para
probar un ejemplo sencillo de extensión de la validación en Struts:
- Generar un bean para un formulario básico.
- Registrar dicho bean en struts–config.xml .
- Crear los métodos que realizarán la validación
extra que se procederá a añadir a la ya incluida por defecto en Struts. - Crear mensajes de error asociados a cada regla
de validación que se añadirá. Esto se realiza a través del fichero MessageResource.properties,
tal como se indicó anteriormente. - Registrar las reglas nuevas de validación que se
apoyarán en los métodos que se crearon en (3) en el fichero validator–rules.xml. - Especificar la validación del formulario básico
cuya bean
se generó en (1) en el fichero validation.xml. - Habilitar el plug-in de validación en struts–config.xml, tal como se indicó anteriormente.
- Crear una jsp con un
formulario básico como el que se generó en (1), y probar utilizando un
contenedor de aplicaciones web (Tomcat, JBoss o similares).
2. Instalación y requisitos
El ejemplo
sencillo que se estudiará más adelante en este documento, se desarrolló y
ejecutó en un entorno Windows XP que
disponía de la distribución Java j2sdk-1.4.2.
Esta distribución puede obtenerse gratuitamente desde la web
de SUN en el enlace:
http://java.sun.com/products/archive/j2se/1.4.2/index.html
Se utilizó una
distribución de Struts de la versión 1.2.8 . El fichero struts-1.2.8-bin.zip correspondiente a dicha distribución puede
obtenerse desde la dirección:
http://struts.apache.org/download.cgi
Una vez
descomprimido el fichero .zip, los siguientes ficheros .jar deben ser visibles en el classpath:
- struts-1.2.8-bin\lib\antlr.jar
- struts-1.2.8-bin\lib\commons–beanutils.jar
- struts-1.2.8-bin\lib\commons-digester.jar
- struts-1.2.8-bin\lib\commons–fileupload.jar
- struts-1.2.8-bin\lib\commons–logging.jar
- struts-1.2.8-bin\lib\commons–validator.jar
- struts-1.2.8-bin\lib\jakarta-oro.jar
- struts-1.2.8-bin\lib\struts.jar
La propia
distribución de Struts, como puede observarse, lleva
ya incorporadas en un fichero .jar las clases del framework Commons Validator utilizadas
por Struts para la validación.
Para desplegar
el ejemplo, se utilizó el contenedor de aplicaciones web
de Tomcat. Se utilizó la distribución jakarta–tomcat-5.0.30.zip, que puede obtenerse gratuitamente desde el enlace:
http://tomcat.apache.org/download-55.cgi
Para el proceso
de desarrollo puede utilizarse, por mayor comodidad, alguno de los IDE’s gratuitos más habituales, como Eclipse o Netbeans. En este caso se utilizó una versión 3.1.0 de
Eclipse, cuyo fichero asociado eclipse-SDK-3.1-win32.zip puede obtenerse gratuitamente desde el enlace:
http://download.eclipse.org/eclipse/downloads/drops/R-3.1-200506271435/index.php
3. Un ejemplo sencillo
3.1. Idea
Se pretende realizar un
ejemplo que ilustre la extensión de la validación en Struts,
tal como se ha comentado antes. Hay que pensar entonces en una regla de
validación que amplíe las funciones de validación incluidas por defecto con el
propio Struts.
En este caso se ha elegido
implementar una regla que prevenga de la introducción de palabras
potencialmente maliciosas si no se establecen ciertos niveles de seguridad.
Por ejemplo, si no se trata
adecuadamente la entrada de datos, en la medida en que estos pueden
corresponderse casi directamente con sentencias sql
podrían introducirse sentencias como drop que podrían borrar datos de las bases de datos de la aplicación.
Existen mecanismos para evitar este tipo de ataques, pero por mayor seguridad,
se implementará una regla de validación que impida la introducción de palabras
potencialmente maliciosas de forma deliberada.
De esta forma, se procederá
a implementar una regla de validación que impida la introducción de palabras
que podrían conformar sentencias sql o de sistema con
fines maliciosos sobre una aplicación web.
La aplicación que se
desarrollará para probar la extensión de la validación en Struts
con dicha regla, estará compuesta por un formulario con un campo donde se
introducirá una cadena de texto, a fin de comprobar si contiene palabras
maliciosas. En caso afirmativo, mostrará un mensaje de error y ofrecerá la
posibilidad de volver a introducir una cadena de texto. Si la cadena no
contiene palabras maliciosas, la aplicación muestra una página informando de
dicho suceso. El siguiente diagrama de estados muestra el funcionamiento de la
aplicación de prueba que se acaba de especificar:
3.2. Creando la nueva regla de
validación
Para extender la validación
de Struts, la primera tarea es crear el método que
contenga la lógica de validación necesaria crear la nueva regla de validación.
En este caso se crea la clase org.autentia.moreValidation.MyValidation,
y en ella los métodos que contendrán la lógica de validación. El código java
correspondiente de esta clase se muestra a continuación.
package org.autentia.moreValidation;
import java.io.Serializable;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.ValidatorAction;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.validator.Resources;
import org.apache.commons.validator.util.ValidatorUtils;
public class MyValidator
implements Serializable{
public static boolean validateWords (
Object object,
ValidatorAction
va,
Field field,
ActionMessages
errors,
HttpServletRequest request)
{
//Parseamos
las palabras maliciosas desde la variable «tokens»
en el fichero validation.xml
StringTokenizer
tokens = new StringTokenizer( field.getVar(«tokens»).toString() );
Vector maliciousWords
= new Vector();
while( tokens.hasMoreTokens() )
{
maliciousWords.add( tokens.nextToken() );
}
//Parseamos
la cadena a valdar desde el campo del fomurlario
String words = ValidatorUtils.getValueAsString(object,
field.getProperty());
//Comprobamos que no haya ninguna palabra potencialmente problematica
//Si hay palabras maliciosas, se emite mensaje de error
if( checkWords(words, maliciousWords)
== false )
{
errors.add(field.getKey(),
Resources.getActionMessage(request, va, field));
return
false;
}
else
//Si todo fue bien se devuelve TRUE
return true;
}
public static boolean checkWords(String words,
Vector maliciousWords)
{
//Transformamos la
cadena en tokens
StringTokenizer
tokens=new StringTokenizer(words,» ;»);
String t = null;
//Para cada token
se comprueba que no sea una palabra maliciosa
while(tokens.hasMoreTokens())
{
t = tokens.nextToken();
for(int i=0;
i<maliciousWords.size();
i++)
{
if( maliciousWords.get(i).toString().equals(t) )
return false;
}
}
//Si todo fue bien
return
true;
}
}
El método que invocará la lógica de la validación, y
que se indicará en la especificación de la regla de validación más adelante, es
validateWords.
Si toda va bien, este método devuelve true. En caso de detectar alguna palabra potencialmente
maliciosa, devuelve false.
Los argumentos que recibe este método son los siguientes:
- Object object: Bean del formulario sobre el que se realizará la validación.
- ValidatorAction va:
Objeto ValidatorAction que se está implementando. - Field field: Objeto que contiene el campo del formulario
que se está validando. - ActionMessages errors: Objeto donde se podrán añadir los mensajes de
error pertinentes si la validación falla. - HttpServletRequest request: Objeto con la petición HTTP que contiene el
formulario a validar.
Los tokens
potencialmente maliciosos con los que se realizará la validación se almacenarán
como una variable en el fichero validation.xml, tal como se indicará más adelante. Se
insertara una variable de nombre tokens, y cuyo
valor será una cadena con todas la palabras maliciosas a considerar separadas
por espacios en blanco.
<var–name>tokens</var–name>
<var-value>eval select delete …
</var-value>
Para acceder al valor de
esta variable se utiliza el método getVar asociado al argumento de entrada field (Objeto tipo Field) del método validateWords, pasándole como argumento el nombre
correspondiente. En este caso será tokens, tal como indica la etiqueta <var–name> .
El método validateWords,
como se ha podido observar, utiliza una función auxiliar checkWords, que realiza las
comprobaciones correspondientes entre los tokens de
la cadena a validar y los tokens potencialmente
maliciosos.
Una vez creada la lógica de
validación para la nueva regla con la clase MyValidatior, se procede a
registrar el método que la realiza en el fichero validator–rules.xml, tal como se comentó
anteriormente. Se introduce también el código javascript que se emplearía para
la validación en el lado del cliente si se optase por ello, además de en el servidor.
Para ello se utiliza la etiqueta <javascript> seguida del código javascript necesario.
<validator
name=»maliciousWords«
classname=»org.autentia.moreValidation.MyValidator«
method=»validateWords«
methodParams=»java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionMessages,
javax.servlet.http.HttpServletRequest«
msg=»errors.maliciousWords«>
<javascript><![CDATA[
function validateWords(form) {
//La siguiente llamada parsea los datos necesarios para la validacion.
//Dicha funcion la genera automaticamente
Struts junto al
//codigo
javascript que deba insertar para la validación
//en el lado
del cliente.
//En este caso, en el
vector this.a0 inserta lo siguiente:
// [0]: Nombre del property del campo a validar del formulario
// [1]: Mensaje de error
que emite la validacion en caso de fallo
// [2]: Funcion para obtener las variables parseadas
desde validation.xml
// arg:
Nombre de la variable (en este caso habra que invocar
«tokens«)
TestForm_maliciousWords();
//Obtenemos los tokens introducidos a la entrada
//Separados por espacios
en blanco
var wordsSpace = form.words.value.split(»
«);
//Obtenemos los tokens
maliciosos a considerar
var
tokens = this.a0[2](«tokens»).split(» «);
//Comprobamos que no existan tokens
maliciosos a la entrada
//Si encuentra alguno
imprime un mensaje y devuelve false
//para evitar que se envie el formulario al servidor (client–side validation)
for(i = 0; i<tokens.length; i++)
{
for(j
= 0; j<wordsSpace.length; j++)
{
//Ahora separamos tokens por «;», para equiparar a StringTokenizer(» ;»)
var aux=wordsSpace[j].split(«;»);
for(l = 0; l<aux.length; l++)
{
if(aux[l] == tokens[i])
{
alert( this.a0[1] );
return false;
}
}
}
}
//Si todo fue bien se
devuelve true
//El formulario se
enviara al servidor
return true;
}]]>
</javascript>
</validator>
En este caso, y dado que el
objetivo de la nueva regla de validación es aumentar la seguridad, no sería
demasiado conveniente implementar dicha validación en el lado del cliente a
través de código javascript.
Supondría un agujero de seguridad en nuestra aplicación, ya que cualquier
posible atacante podría obtener fácilmente el “truco” del filtro implementado
en la validación. No obstante, la validación en el lado del cliente se considera
importante y por ello se procederá a dar
las directrices de implementación para el ejemplo concreto que se esta
considerando.
En el campo msg se especifica
el mensaje asociado a la etiqueta errors.maliciousWords en el fichero MessageResource.properties, como
mensaje a emitir por la validación en caso de error. Su contenido es el
siguiente:
errors.maliciousWords={0} contiene palabras maliciosas.
En este punto ya se tiene
generada una extensión del Commons Validator utilizado por Struts,
que podría reutilizarse en futuros proyectos.
3.3. Creación del formulario de
prueba
Para poder realizar pruebas
con la nueva regla de validación, es necesario crear un formulario para
introducirlo en una jsp.
Se implementa primero la
clase asociada a la bean de dicho formulario con sus métodos set/get
correspondientes. El atributo words contendrá la
cadena a validar que se introducirá como entrada en el formulario.
package org.autentia.moreValidation;
import org.apache.struts.validator.ValidatorForm;
public class TestForm
extends ValidatorForm {
protected
String words;
public void setWords(String words)
{
this.words = words;
}
public String getWords() {
return this.words;
}
}
Se registra esta bean en el
fichero struts–config.xml.
<form-bean
name=»TestForm«
type=»org.autentia.moreValidation.TestForm«>
<form-property
name=»words» type=»java.lang.String«/>
</form–bean>
Se define también la acción
asociada al proceso del formulario. En este caso la acción simplemente debe
facilitar la transición a la página que confirme la no existencia de palabras
potencialmente maliciosas. Esta transición se llevará a cabo si la validación
asociada a la bean
del formulario (superclase ValidatorForm) lo permite.
La lógica de la acción sería
la siguiente:
package org.autentia.moreValidation;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
public
final class TestAction extends Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return (mapping.findForward(«success«));
}
}
Se registra la acción en el
fichero struts–config.xml :
<action
path=»/WordsValidation«
type=»org.autentia.moreValidation.TestAction«
name=»TestForm«
scope=»request«
validate=»true«
input=»/pages/testWords.jsp«>
<forward name=»success» path=»/pages/saludo.jsp«/>
</action>
3.4. Especificación de la validación
para el formulario de prueba
El siguiente paso antes de
implementar una jsp de prueba, consiste en
especificar la validación del formulario de prueba que se acaba de definir, a
fin de aplicar la nueva regla de validación implementada. Como se comentó
anteriormente, esto se realiza en el fichero validation.xml, con las
siguientes líneas:
<form-validation>
<formset>
<form name=»TestForm«>
<field property=»words»
depends=»maliciousWords«>
<arg
key=»form1.text»/>
<var>
<var-name>tokens</var-name>
<var-value>eval select delete like var
update where drop database create alter cp mv ls cat host cmd uname px pwd
uptime chmod ps grep awk cut echo find kill ln passwd who</var-value>
</var>
</field>
</form>
</formset>
</form–validation>
Se asocia la validación de
la regla maliciousWords
al property etiquetado como words, que almacenará la cadena
de entrada a validar en el formulario de prueba.
La etiqueta <var>
contiene una variable de nombre tokens que contiene una cadena con las palabras
potencialmente maliciosas que se considerarán separadas por espacios, tal como
se comentó anteriormente.
El argumento asociado al
mensaje de error es la cadena etiquetada como form1.text en el fichero MessageResources.properties,
que contendrá el nombre del campo del formulario (cadena).
form1.text=Cadena
3.5. Generación de jsp’s para probar
validación del formulario
El último paso antes de iniciar las pruebas consiste
en implementar la jsp que contendrá el formulario que
utilizará la nueva regla de validación (maliciousWords). Su código podría ser algo como lo
siguiente:
<%@
page contentType=»text/html;charset=UTF-8″
language=»java» %>
<%@
taglib uri=»/WEB-INF/struts–html.tld» prefix=»html» %>
<%@
taglib uri=»/WEB-INF/struts–bean.tld» prefix=»bean» %>
<html:html>
<head>
<title>Extendiendo la validación en Struts</title>
</head>
<body>
<html:form action=»/WordsValidation»
method=»post»
onsubmit=»return validateTestForm(this);»>
<p>
<h2><bean:message
key=»intro.texto«/></h2>
</p>
<bean:message
key=»form1.text»/>
<html:text
property=»words»/>
<html:submit><bean:message key=»boton.comprobar«/></html:submit>
<p>
<h3><font color=»red»><html:errors/></font></h3>
</p>
<html:javascript formName=»TestForm«/>
</html:form>
</body>
</html:html>
En este caso, se ha optado por realizar la validación
también en el lado del cliente, aparte de en el servidor, a través de código javascript. Este
código javascript
se genera a partir de la validación especificada para TestForm en los ficheros validator–rules.xml y validation.xml, utilizando la etiqueta <html:javascript> indicada:
<html:javascript formName=»TestForm«/>
Para hacer efectiva esta validación en el lado del
cliente, se edita el campo onsubmit en la etiqueta <html:form>. Este campo
contendrá una llamada a la función validateTestForm que es la que realizará la validación en el
lado del cliente utilizando el código javascript implementado anteriormente en el fichero validator–rules.xml. Si
esta función devuelve true
se enviará el formulario al servidor. Si devuelve false el formulario no será enviado al servidor.
<html:form action=»/WordsValidation»
method=»post»
onsubmit=»return validateTestForm(this);»>
La
función validateTestForm la genera automáticamente Struts para realizar la validación en el cliente junto al
resto de código javascript
implementado para dicho fin. De hecho, cuando genera la validación
correspondiente en el lado del cliente siempre genera una función validateXXX donde
XXX corresponde con el nombre
asociado al formulario. Esta función es la que se encargará de llamar a las
funciones javascript
de las reglas que correspondan a la validación del formulario.
Si solo se quisiera realizar validación en el lado
del servidor, se podría utilizar una versión de la jsp
como la siguiente:
<%@ page contentType=»text/html;charset=UTF-8″ language=»java» %>
<%@ taglib uri=»/WEB-INF/struts–html.tld» prefix=»html» %>
<%@ taglib uri=»/WEB-INF/struts–bean.tld» prefix=»bean» %>
<html:html>
<head>
<title>Extendiendo la validación en Struts</title>
</head>
<body>
<html:form action=»/WordsValidation» method=»post»>
<p>
<h2><bean:message key=»intro.texto«/></h2>
</p>
<bean:message
key=»form1.text»/>
<html:text
property=»words»/>
<html:submit><bean:message key=»boton.comprobar«/></html:submit>
<p>
<h3><font color=»red»><html:errors/></font></h3>
</p>
</html:form>
</body>
</html:html>
Como puede verse, se ha eliminado la etiqueta <html:javascript> y el campo onsubmit de la etiqueta <html:form>
.
Se implementa igualmente la página saludo.jsp a la
que dará paso la acción del formulario de la jsp
anterior si la cadena no contiene palabras potencialmente maliciosas.
<?xml version=»1.0″?>
<html>
<head>
<title>Extendiendo la validación en Struts</title>
</head>
<body>
<h2>La cadena de texto no contiene
palabras maliciosas</h2>
</body>
</html>
Con esto ya se dispone de todas las partes necesarias
para ejecutar el ejemplo de prueba explicado inicialmente. Sólo queda compilar
y empaquetar la aplicación en un fichero .war, y desplegarlo en un servidor de aplicaciones web.
3.6. Ejecución
Una vez compilado, empaquetado y desplegado el
proyecto en un contenedor de aplicaciones web, la
ejecución del ejemplo produce los siguientes resultados. Se mostrará la
correspondencia entre el flujo de páginas de la aplicación y el diagrama de
estados de la misma que se diseñó al principio de este apartado.
3.6.1. Validación en el lado del cliente
Si se empleara la jsp
indicada anteriormente para realizar la validación en el lado del cliente,
aparte de en el servidor, algunas pruebas darían los siguientes resultados:
1. Relleno
del formulario (palabras maliciosas)
2. Relleno
del formulario (ok)
3.6.2. Validación sólo en el lado del servidor
Si se empleara la jsp
indicada anteriormente para realizar la validación sólo en el lado del
servidor, algunas pruebas darían los siguientes resultados:
1. Relleno
del formulario (palabras maliciosas)
2. Relleno
del formulario (ok)
4. Conclusiones
Como se ha podido comprobar,
extender los mecanismos de validación en Struts no
debería ser una tarea excesivamente compleja para cualquier iniciado en Struts.
Cabe señalar también la
importancia de establecer los mecanismos de validación oportunos en cualquier
aplicación en general, y en este caso sobre aquellas construidas sobre Struts, a fin de generar software más robusto y fiable.
El proceso de generar dicha
validación ya se ha visto que no es excesivamente complicado; el mayor trabajo
reside probablemente en detectar las necesidades de validación de cada
aplicación.
En este sentido, comentar
que el ejemplo implementado pretende fundamentalmente ilustrar la forma de
extender los mecanismos de validación en Struts, y no
como generar un filtro léxico para formularios de absoluta fiabilidad. No
obstante, con un poco de investigación y ligeras modificaciones, el ejemplo
constituye un buen primer paso para aquellos lectores interesados en aumentar
la seguridad en sus aplicaciones con Struts.
5. Fuentes
- Programming Jakarta Struts (O’Reilly).
Chapter 11: The Validator Framework
http://www.oreilly.com/catalog/0596006519/chapter/ch11.pdf
- Artículo: Using the Validator
Framework with Struts
http://www.onjava.com/pub/a/onjava/2002/12/11/jakartastruts.html
- Artículo: Struts Validator Framework with Example
http://www.roseindia.net/struts/struts_validator_framework.shtml