-
Notifications
You must be signed in to change notification settings - Fork 2
Hdiv
UDA ofrece una librería de seguridad que integra x38 y Hdiv. En esta wiki se detallan los pasos necesarios para su instalación y uso.
La librería de Hdiv realiza tres tipos de validaciones:
- Control de acceso
- Validaciones de editables
- Validaciones de integridad
La configuración de seguridad se podrá modificar desde la consola modificada teniendo esta prioridad sobre la definida en la propia aplicación.
Se trata de determinar qué URLs quedan accesibles para el usuario. Por defecto ninguna URL será permitida a no ser que se habilite desde la parte servidora de la aplicación. Más adelante se muestra cómo habilitar los accesos.
Se trata de validar los datos enviados en campos de texto. Existe una validación por defecto que podrá ser completada por el desarrollador.
Se trata de validar los datos enviados en campos de texto. Existe una validación por defecto que podrá ser completada por el desarrollador.
La librería de Hdiv forma parte de la x38 desde la versión 5.0.0. Se cargarán las dependencias necesarias al hacer uso de la x38.
El los proyectos web (WAR):
-
Añadir el listener y el filtro de Hdiv en el
web.xml
. El filtro debe ser el primero en registrarse. Para ello, se situará por delante del filtro de UDA:<!-- Hdiv Init Listener --> <listener> <listener-class>org.hdiv.listener.InitListener</listener-class> </listener> <!-- Hdiv Validator Filter --> <filter> <filter-name>ValidatorFilter</filter-name> <filter-class>org.hdiv.filter.ValidatorFilter</filter-class> </filter> <filter-mapping> <filter-name>ValidatorFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
Añadir una clase de configuración que extienda de la clase
UDA4HdivConfigurerAdapter
. Un ejemplo básico sería el siguiente:@Configuration public class UDA4HdivConfig extends UDA4HdivConfigurerAdapter { @Override protected String getHomePage() { return "/"; } @Override protected String getLoginPage() { return "/loginPage"; } protected String getDashboardUser() { return "dashboard-admin"; } protected String getDashboardPass() { return "password"; } @Override public void addCustomExclusions(final ExclusionRegistry registry) {} @Override public void addCustomRules(final RuleRegistry registry) {} @Override public void customConfigureEditableValidation(final ValidationConfigurer validationConfigurer) {} }
Más adelante en el punto Configuración se explicará con más detalle la configuración de la librería.
En el método getHomePage se establecerá la URL por la que se accede a la aplicación.
En getLoginPage se especifica la URL de la página de login.
En getDashboardUser y getDashboardPass se especifica el usuario y contraseña de acceso al dashboard de Hdiv. En este dashboard se muestra la información de seguridad relativa a la aplicación.
Para acceder a esta vista de información: {appContextPath}/hdiv-services/dashboard
Para añadir exclusiones de validación se hará uso del método addCustomExclusions.
Si se necesitan crear nuevas reglas de validación, se hará uso del método addCustomRules. Aquí se especificará un nombre de validación y los patrones aceptados y/o rechazados.
Un ejemplo de validación en la que se aceptan únicamente valores numéricos sería:
registry.addRule("numerico").acceptedPattern("^[0-9]+$");
Para asignar las reglas existentes a URLs o parámetros se hará uso de customConfigureEditableValidation.
Un ejemplo de asignación de la regla de valores booleanos sería el siguiente:
validationConfigurer
.addValidation("/.*")
.forParameters("parameter.name")
.rules("boolean")
.target(ValidationTargetType.CLIENT_PARAMETERS);
El atributo CLIENT_PARAMETERS se refiere a parámetros creados directamente en el cliente sin ser enviados desde el servidor (JavaScript).
Cambiar el archivo mvc-config.xml para que el base scan encuentre el archivo de configuración.
Para permitir el acceso a URLs será necesario que estas estén creadas mediante el tag de Spring spring:url o permitidas desde el controlador. El método aconsejado es mediante el tag de Spring, siendo la habilitación desde el controlador el método utilizado para URLs creadas en cliente (javascript).
Las peticiones realizadas a URLs no generadas de las siguientes maneras serán bloqueadas.
Esta forma de generar las URLs hace que el servidor sea el encargado de crearlas y de registrarlas. En las URLs se añadirá un parámetro de seguridad encargado de identificar el enlace.
Incorrecta:
<a class="nav-link" href="/appContext/url">
Adecuada:
<spring:url value="/url" var="url"/>
<a class="nav-link" href=${url}>
Las URLs que coinciden con el siguiente listado están excluidas de validación en la configuración de la librería, y por lo tanto no requieren del tag de Spring: /scripts/.*, /styles/.*, /fonts/.*, /error, /*.gif
Se ha implementado una herramienta que permite habilitar URLs desde el controlador: @UDALink
.
Esta herramienta se utiliza en forma de anotación. Consta de dos partes, identificación del link y accesos permitidos. Al acceder al método del controlador con esta anotación, se habilitará el acceso a los links definidos en linkTo. Por ejemplo, un método anotado de la siguiente manera permite el acceso a las peticiones de los métodos marcados como UDALink edit y remove:
@UDALink(name = "get", linkTo = {
@UDALinkAllower(name = "edit" ),
@UDALinkAllower(name = "remove" )
})
Una condición para el uso de esta anotación, es que en el caso de existir path variables en el mapping de los métodos a habilitar, el nombre de las path variables debe coincidir con el nombre de atributo del objeto enviado en la response.
Solo se permitirá el acceso a los métodos que coincida esta regla, es decir, siguiendo con el ejemplo anterior no se podrá editar o eliminar ningún objeto que no haya sido devuelto en el método con nombre get:
@UDALink(name = "remove")
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
El atributo id debe existir en el objeto devuelto por el método get.
Si el método al que se quiere dar acceso se encuentra en otro controlador, se hara uso de el atributo linkClass de la anotación UDALinkAllower dentro de UDALink:
@UDALink(name = "get", linkTo = {
@UDALinkAllower(name = "edit", linkClass = CustomOtherController.class)
})
Hay casos en los que no todas las entidades devueltas por el método del controlador deben tener acceso a los links anotados. Para discriminar parte de estos recursos, se hará uso del atributo allower:
@UDALink(name = "get", linkTo = {
@UDALinkAllower(name = "edit", allower = CustomController.class)
})
Este atributo define la clase en la que se encuentra el predicado con la lógica de clasificación. El predicado debe ser un método público y estático que devuelva un objeto de tipo LinkPredicate<Tipo_De_Entidad>
con la implementación del método test. El método test recibe el objeto LinkInfo
como parámetro:
public class LinkInfo<T> {
private final String linkId;
private final T entity;
private final HttpServletRequest request;
}
A continuación se muestra un ejemplo de implementación:
public static LinkPredicate<Entidad> getEntidadLinkPredicate() {
return new LinkPredicate<Entidad>() {
@Override
public boolean test(LinkInfo<Entidad> linkInfo) {
return !linkInfo.getEntity().isClosed();
}
};
}
Si una entidad tiene subentidades y queremos que todas las claves vayan cifradas, deberemos añadir el atributo allowSubEntities=true
:
@UDALink(name = "get", linkTo = {
@UDALinkAllower(name = "edit", allowSubEntities=true),
@UDALinkAllower(name = "remove"),
@UDALinkAllower(name = "getProvincias", linkClass=TableComarcaController.class, allowSubEntities=true),
@UDALinkAllower(name = "getApellidos", linkClass=TableUsuarioController.class),
@UDALinkAllower(name = "filter")
})
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public @ResponseBody Resource<X21aAlumno> get(@PathVariable BigDecimal id) {
X21aAlumno x21aAlumno = new X21aAlumno();
x21aAlumno.setId(id);
x21aAlumno = this.x21aAlumnoService.find(x21aAlumno);
TableX21aAlumnoController.logger.info("[GET - findBy_PK] : Obtener X21aAlumno por PK");
return new Resource<X21aAlumno>(x21aAlumno);
}
Las claves primarias de una clave con Hdiv pueden ir cifradas desde el controlador a través del model&view de Spring, a continuación se muestra un ejemplo:
//caso1
model.addAttribute("bandeja", bandeja);
//caso2
model.addAttribute("bandejaCifrada",new IdentifiableModelWrapperImpl<Bandeja>(bandejaCifrada, "codBandeja"));
En el primer caso se mandan los datos como siempre, solo que la entidad no va cifrada, en el segundo caso la entidad iría cifrada, para ello la definición es la siguiente, el nombre de la variable, el WrapperImpl con el tipo de tu propia clase, la variable y por último el nombre del campo clave de tu clase. A la hora de mostrarlo en la JSP quedaría así:
//caso1
<form:form modelAttribute="bandeja" id="ejemplo_filter_form" action="${url}" method="POST">
//caso2
<form:hidden path="codBandeja" id="codBandejaEjemplo" value="${bandejaCifrada.entity.codBandeja}"/>
En el caso 1, haremos el populate de todos los los datos de forma convencional, por ejemplo, informando al modelAtribute.
En el caso 2, para poder usar la clave primaria, para mostrar o para luego reutilizarla, invocaremos a la variable ${bandejaCifrada.entity.codBandeja}
.
El envío de datos al servidor será de dos tipos:
- Formularios con tags de Spring
- Peticiones tipo REST
Los formularios deben hacer uso de los tags de Spring y definir el campo action.
<spring:url value="/url" var="url"/>
<form:form id="form_id" action="${url}">
Es importante incluir el taglib de spring-form.
<%@ taglib prefix="form" uri="/WEB-INF/tld/spring-form.tld"%>
Los datos estáticos de los formularios como combos, radios, checkbox, etc., se deberán cargar en tiempo de renderizado.
Lo más común es emplear el modelo para añadir estos datos como atributos:
Controller
Map<String,String> att = new LinkedHashMap<String,String>();
att.put("value1", "value1Name");
att.put("value2", "value2Name");
model.addAttribute("attname", att);
JSP
<form:select path="name" id="estado_filter_table" class="rup-combo" items="${attname}"/>
Controller
model.addAttribute("attname2", att2ValueList);
JSP
<form:select path="name2" class="rup-combo">
<form:option value=""> </form:option>
<form:options items="${attname2}" itemLabel="desc" itemValue="key"/>
</form:select>
Es importante comprender que los datos permitidos en un formulario están asociados al action del mismo. Si se modifica la URL del formulario, esta no corresponderá con los parámetros permitidos y la petición será bloqueada.
La librería considera que los campos definidos como hidden no son editables, con lo que si estos sufren modificaciones (su valor no corresponde al del momento de renderizado del formulario), la petición será bloqueada.
Si hay campos ocultos en los que las modificaciones están permitidas, estos deberán ser inputs ocultos.
<form:input path="parameter" style="display: none"/>
Las entidades deberán ser de tipo SecureIdContainer
o SecureIdentifiable
y siempre serán representadas por un identificador único. Este identificador viajará cifrado y se proporcionará el valor original en el campo con nombre nid
.
SecureIdentifiable: En caso de que la entidad posea un atributo llamado id
o requiera de clave compuesta.
Se crearán los métodos getId y setId.
SecureIdContainer: Si la entidad tiene un atributo identificativo (código cuyo nombre de atributo es distinto de id
) o si el objeto no es una entidad en sí misma, pero contiene una, esta implementará SecureIdentifiable
. Para conocer el atributo identificador, se anotará con @TrustAssertion(idFor = EntidadActual.class)
.
Un ejemplo de SecureIdContainer.
Clase entidad:
public class Entidad implements java.io.Serializable, SecureIdContainer {
@TrustAssertion(idFor = Entidad.class)
private Integer codEntidad;
}
Clase que no es una entidad en sí, pero hace uso de una:
public class EntidadDAO implements java.io.Serializable, SecureIdContainer {
@TrustAssertion(idFor = Entidad.class)
private Integer codEntidad;
}
Al enviar las entidades a cliente, se harán en forma de Resource
.
new Resource<Entidad>(entidad);
public @ResponseBody Resource<Entidad> get(@PathVariable String id)
public @ResponseBody TableResourceResponseDto<Entidad> filter()
La librería x38 hace uso de la clase TableResourceResponseDto
para enviar las entidades como Resources
y esta clase es compatible con el componente tabla.
Las URLs de peticiones que hagan uso de path variables deberán cumplir con el siguiente patrón:
- La última variable corresponderá al identificador de la entidad.
- Las variables en la URL que correspondan a la entidad y no estén modificados deberán tener el mismo nombre que el atributo de la propiedad.
- Se recomienda que las variables estáticas de la URL sean una enumeración para controlar el valor de los mismos. Por ejemplo una variable con nombre
estado
cuyos valores se esperan entre activo e inactivo, se recomienda que sea un enumerado al menos en el path.
En caso de que el valor de una variable no quiera ser validado por integridad, se marcará en el controlador de la siguiente manera:
@PathVariable @TrustAssertion(idFor = NoEntity.class) Integer value
La librería ofrece la posibilidad de añadir configuración a la aportada por defecto.
Las validaciones se configurarán desde la clase de configuración que extiende de UDA4HdivConfigurerAdapter
.
A continuación, se exponen las opciones de configuración:
Las URLs añadidas como urlexclusions no serán validadas. Se establecerá la URL (puede contener expresiones regulares) y se podrá especificar el verbo del método HTTP al que aplica.
@Override
public void addCustomExclusions(final ExclusionRegistry registry) {
registry.addUrlExclusions("/url.html").method("GET");
}
Como parte especial de URLs excluídas de validación se encuentran las URLs de entrada a la aplicación y login. Estas se configuran de la siguiente manera:
@Override
protected String getHomePage() {
return "/";
}
@Override
protected String getLoginPage() {
return "/loginPage";
}
Se permite especificar la validación de valor de parámetro por nombre de parámetro y URL. Esta regla se compone de la URL en la que se aplica la validación, el patrón aceptado, el rechazado y el nombre que se da a la regla.
En la regla se podrá especificar el patrón aceptado y/o el rechazado.
Patrón de valores aceptados en el parámetro que se compone de expresiones regulares.
Patrón de valores rechazados en el parámetro que se compone de expresiones regulares.
A continuación se muestra un ejemplo de regla de validación de editables:
@Override
public void addCustomRules(final RuleRegistry registry)
registry.addRule("customValidation").acceptedPattern("^[a-zA-Z0-9@.\\-_]*$");
}
@Override
public void customConfigureEditableValidation(final ValidationConfigurer validationConfigurer){
validationConfigurer.addValidation(".*").rules("customValidation");
}
Al igual que se ofrece una opción para evitar la validación por URLs, se permite excluir las validaciones de parámetros en concreto. Estas exclusiones pueden especificarse por URL siguiendo una expresión regular.
A continuación se muestra un ejemplo de configuración para la exclusión del parámetro paramName
para todas las URLs que empiezan por section/.
@Override
public void addExclusions(ExclusionRegistry registry) {
registry.addParamExclusions("paramName").forUrls("/section/.*");
}
En ocasiones, hay parámetros que son generados en el cliente y por lo tanto, desconocidos para la parte servidora. Una petición con este tipo de parámetros sería bloqueada por la librería por tratarse de datos no autorizados por el servidor. Si es necesario que estos parámetros sigan siendo creados en la parte cliente (JavaScript, HTML) se deberá añadir una validación indicando que se tratan de parámetros creados en el cliente y son esperados por el servidor.
Esta configuración se hará de las siguientes maneras:
-
Parámetro generado en cliente con validación por defecto:
@Override public void customConfigureEditableValidation(final ValidationConfigurer validationConfigurer){ validationConfigurer.addValidation("/.*") .forParameters("paramName") .target(ValidationTargetType.CLIENT_PARAMETERS; }
-
Parámetro generado en cliente con validación personalizada:
@Override public void customConfigureEditableValidation(final ValidationConfigurer validationConfigurer){ validationConfigurer.addValidation("/.*") .forParameters("paramName") .rules("customValidation") .target(ValidationTargetType.CLIENT_PARAMETERS).disableDefaults(); }
Para el manejo de excepciones personalizadas se puede usar un hander propio, para ello la definición en el mvc-config.xml
quedaría de esta forma:
<!-- Configurar Excepciones propagadas en los Controller -->
<bean class="com.ejie.x38.hdiv.config.WebConfig">
<property name="handlers">
<list>
<bean class="com.ejie.x21a.handler.X21aExceptionHandler" />
</list>
</property>
</bean>
Para la subida de ficheros, hay que definir en el mvc-config.xml
el siguiente bean o uno personalizado que extienda de este:
<!-- Permite la subida de ficheros -->
<bean id="multipartResolver" class="org.hdiv.web.multipart.HdivCommonsMultipartResolver" />
Cuando se despliega una aplicación que hace uso de la librería Hdiv, también se despliega un dashboard dónde poder ver cómo de securizada está la aplicación, sus entidades etc.
Para poder acceder hay que añadir /hdiv-services/dashboard
a la URL tras el nombre de la aplicación. Antes de poder acceder, nos aparecerá un formulario para ingresar el nombre de usuario y su contraseña, ambos están definidos en la clase UDA4HdivConfig
. El formulario es el siguiente:
A continuación, volverá a aparecer el mismo formulario, pero esta vez habrá que ingresar el nombre de usuario y contraseña usados para acceder al panel de gestión de WebLogic. A continuación, una captura que muestra el formulario:
Una vez ingresados ambos usuarios, se mostrará el dashboard:
Por el momento al menos, no se pueden usar los combos mixtos en las aplicaciones que tengan Hdiv activado. El motivo es simple, Hdiv funciona con identificadores cifrados y al utilizar combos mixtos, van a existir identificadores sin cifrar, dando lugar a un bloqueo por parte de Hdiv por ser un problema de seguridad.
La documentación y la información contenida en estas páginas se ofrecen bajo licencia
El plugin , las extensiones para Hibernate Tools, las plantillas de generación de código, las librerías de utilidades
y los componentes RUP se ofrecen con arreglo a la
European Union Public Licence (EUPL), exclusivamente en su versión 1.1.