SERVEI DE LOPD















Introducció

Propòsit

El servei de LOPD de Canigó permet assignar un determinat nivell de protecció a les dades de l'aplicació que l'utilitzi.

Context i Escenaris d'Ús

El servei de LOPD es troba dins dels serveis generals de Canigó.
El seu ús és necessari en cas de voler protegir dades sensibles de l'aplicació o d'enregistrar el seu accés.

Versions i Dependències

Les dependències descrites a la següent url són requerides per tal de compilar i fer funcionar el projecte:
Dependències Servei de LOPD

A qui va dirigit

Aquest document va dirigit als següents perfils:

  1. Programador. Per conèixer l'ús del servei.
  2. Arquitecte. Per conèixer quins són els components i la configuració del servei.

Glossari

LOPD: Llei Orgànica de Protecció de Dades

Descripció Detallada

Arquitectura i Components

Introducció

El servei LOPD ofereix suport a les aplicacions basades en Canigó per facilitar el compliment de la LOPD. En aquest sentit, el servei disposa de dos vessants diferenciades per a complir amb aquest objectiu. Aquestes són per una banda la configuració de les dades que són sensibles dins el model i a quin nivell ho són, i per altra banda dels mecanismes a aplicar en cadascun d'aquests nivells dins l'execució de l'aplicació.

Components del Servei

Com ja s'ha comentat anteriorment, el servei es pot dividir en dos parts:

  • Definició del nivell de les dades.
  • Configuració dels mecanismes de seguretat de la LOPD.

S'ha volgut dotar al servei de la màxima flexibilitat possible, fent-lo altament configurable i adaptable a nous requisits que pugessin sorgir en futurs canvis de la llei.

Definició del nivell de les dades

Les classes principals d'aquest component són:

  • LOPDAttributeSourceImpl: classes que compleix la interfície LOPDAttributeSource i que conté un mètode getLevel el qual rep com a paràmetres una classe i un nom d'atribut de la mateixa i retorna el nivell de protecció de LOPD del mateix.
Propietat Obligatori Descripció Valor per defecte
LOPDAttributes Properties que conté per un atribut d'una classe a quin nivell pertany. Es poden fer servir comodins. Per exemple:
<props>
	<prop key="net.gencat.ctti.canigo.samples.prototip.model.Category.*">HIGH_LEVEL</prop>
	<prop key="net.gencat.ctti.canigo.samples.prototip.model.Category.descn">MED_LEVEL</prop>
</props>

En aquest cas s'està indicant que tots els atributs de la classes Category són de nivell alt. Cas d'haver-hi dos regles que es compleixin per un atribut, sempre s'aplicarà la regla més restrictiva. Així doncs, el nivell de l'atribut descn de la classe Category seria mig per l'exemple anterior.
 
Levels No Es tracta d'un hashmap calculat a partir del properties anterior i que es fa servir per fer les cerques dels nivells de les dades sensibles null
  • Level. Classe de suport que ens indica els tres nivells d'aplicació de la LOPD.

Mecanismes de seguretat

Com el seu nom indica, la LOPD afecta a les dades del model de les aplicacions. És en accedir a les dades doncs, on s'ha d'establir un punt d'intervenció per a revisar quins mecanismes de seguretat s'ha d'aplicar.

És altament recomanable aïllar de forma clara aquells objectes del model que contindran dades sensibles pel que s'haurà de separar l'accés a aquesta informació en objectes de negoci, BO, a banda dels que treballen amb dades no sensibles de l'aplicació.

Per aquest tipus de BO que tracten dades sensibles es crearà un proxy específic. Aquest serà el mateix que per la gestió de la transaccionalitat que es defineix al servei de persistència, però tindrà uns interceptor que permetran actuar abans i després de llegir o canviar una dada del model.

L'interceptor previ a l'accés al model actuarà en el moment de fer una inserció o una actualització de les dades. En aquest moment, s'examinarà si algun dels objectes que es reben per paràmetre conté alguna dada sensible. Per fer-ho, S'interrogarà cadascun d'ells contra l'objecte LOPDAttributeSource definit anteriorment. Cas que algun dels atributs tingui definit un nivell LOPD, s'aplicarà els mecanismes associats a aquest nivell.

L'interceptor posterior a l'accés al model en canvi, actuarà en el moment de recuperar dades del model. Quan el mètode retorna les dades, s'examinarà els objectes retornats i es procedirà de la mateixa forma que a l'nterceptor previ.
A continuació es mostra el diagrama de classes d'aquest component:
Les classes principals d'aquest component són:

  • LOPDInterceptorImpl: classe que implementa la interfície LOPDInterceptor. Aquesta classe te de dos subclasses el Pre i el Post interceptor que actuen abans i després d'accedir a les dades.
Propietat Obligatori Descripció Valor per defecte
LOPDAttributeSource Configuració de les dades que són sensibles i a quin nivell ho són  
lowLevelHandlers No Llista de handlers a aplicar quan la dada és de nivell bàsic null
midLevelHandlers No Llista de handlers a aplicar quan la dada és de nivell mig null
highLevelHandlers No Llista de handlers a aplicar quan la dada és de nivell alt null
enabled No Si els llistats de handlers de tots els nivells són nulls, es posa a false pero no aplicar l'interceptor. true
  • LOPDAttributeSource: classe que ja s'ha explicat anteriorment i que conté les dades que són sensibles i a quin nivell de la LOPD.
  • LOPDHandler: Classe que conté un mètode anomenat handle que és l'encarregat d'aplicar el mecanisme de seguretat que toqui pel nivell on està configurat. A continuació es veuran els tres handlers que proporciona el servei: registre d'accés a la dada, xifratge i desxifratge de dades.
Handler de registre d'accés

Aquest handler aplica el mecanisme de seguretat de registrar els accessos a les dades sensibles. La implementació proposada fa servir el servei de seguretat per recollir les dades de l'usuari que està accedint a la dada i el servei de traces per registrar la traça amb la informació de la dada accedida, data i hora, usuari que ho ha fet i tipus d'accés.

L'única classe específica del component és el LoggingHandler que te el servei de seguretat i el de traces, o logging. Al mètode handle és on realitza l'escriptura de la traça de registre d'accés.

Handlers de xifrat/desxifrat

Es tracta de dos handlers que permeten aplicar el mecanisme de seguretat que xifra les dades al suport on s'emmagatzemen. Un dels handler encripta la dada abans de passar-la al model i l'altre la desencripta per poder ser mostrada a l'aplicació. D'aquesta manera s'aconsegueix que l'aplicació treballi amb la dada en format de texte plà, però es desi a la base de dades encriptada.

Les principals classes del component són:

  • DecryptDataHandler: handler que al mètode handle crida al element cipher per a que desencripti la dada. Un cop desencriptada la dada, modifca l'objecte amb el nou valor.
  • EncryptDataHandler: handler que al mètode handle crida al element cipher per a que encripti la dada. Un cop encriptada la dada, modifca l'objecte amb el nou valor.
  • Cipher: interfície que ofereix un mètode per encriptar un String i un altre per desencriptar-lo.
  • BouncyCastleAESCipherImpl: implementació de la interfície Cipher que es basa en l'algorisme AES i el proveïdor BouncyCastle. És necessari passar-li per configuració una key de tipus AES amb la que realitza les operacions de xifratge.

Es pot trobar tota la documentació JavaDoc i el codi font referent aquests components a les següents urls:

JavaDoc: http://canigo.ctti.gencat.net/confluence/canigodocs/site/canigo2_3_15/canigo-services-lopd/apidocs/index.html
Codi Font:  http://canigo.ctti.gencat.net/confluence/canigodocs/site/canigo2_3_15/canigo-services-lopd/xref/index.html

Instal.lació i Configuració

Instal.lació

La instal.lació del servei requereix de la utilització de la llibreria 'canigo-services-lopd' i les dependències indicades a l'apartat 'Introducció - Versions i Dependències'.

S'ha d'introduïr la següent dependència en el pom.xml de l'aplicació:

<dependency>
	<groupId>canigo</groupId>
	<artifactId>canigo-services-lopd</artifactId>
	<version>${canigo.version}</version>
</dependency>
Important

Aquest servei només està disponible a partir de la versió 2.3.15 del framework.

Configuració

El servei ja te una configuració per defecte. L'únic que ha de configurar l'usuari són les dades del model que apliquen a la LOPD i en quin nivell.

Aquesta configuració es pot fer en un fitxer anomenat canigo-services-lopd.xml on tindrem una configuració com la següent:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 	<import resource="classpath:/spring/default-canigo-services-lopd.xml" />
	
 	<bean id="LOPDAttributesSource" class="net.gencat.ctti.canigo.services.lopd.definition.impl.LOPDAttributeSourceImpl">
 		<property name="LOPDAttributes">
 			<props>
 				<prop key="net.gencat.ctti.canigo.samples.prototip.model.Category.*">HIGH_LEVEL</prop>
 				<prop key="net.gencat.ctti.canigo.samples.prototip.model.Category.descn">MED_LEVEL</prop>
 			</props>
 		</property>
 	</bean>
	
</beans>

Com es pot veure només s'ha configurat les dades que apliquen a la LOPD. En el cas de l'exemple tots els atributs de la classe Category són de nivell alt, menys el descn que és de nivell mig. Podeu consultar el contingut del fitxer de configuració per defecte del servei, default-canigo-services-lopd.xml a l'apèndix A.

A més d'aquest fitxer XML, s'ha d'afegir al servei de configuració un nou fitxer de properties que contindrà la clau simètrica que es fa servir per l'encriptació de dades. Aquest fitxer es pot anomenar lopd.properties i pot estar dins un directori anomenat lopd. El contingut del mateix ha de ser semblant a aquest:

lopd.secretkey=000102030405060708090a0b0c0d0e0f

On només hi ha una propietat que és la clau que es farà servir per encriptar i desencriptar dades.

NOTA: És molt important no perdre aquest clau en cada entorn ja que les dades encriptades a la BD no podrien ser desencriptades cas de perdre's la mateixa.

Per tal de facilitar la creació d'aquestes claus, el servei facilita un generador de claus AES. Consulteu l'apèndix B per veure'n l'ús.

Gestió Excepcions

El servei conté una excepció pròpia per la gestió dels possibles errors que puguin esdevindre durant la configuració o l'execució del mateix.
Aquesta excepció és la classe anomenada net.gencat.ctti.canigo.services.lopd.exception.LOPDException.
Es recomana gestionar aquesta excepció amb el servei d'excepcions de Canigó.
Els missatges d'error propis d'aquest tipus d'excepció són:

Codi Missatge
net.gencat.ctti.canigo.services.lopd.exception.invalidKey Invalid 128 AES key provided {0}
net.gencat.ctti.canigo.services.lopd.exception.illegalblocksize the length of data provided to a block cipher is incorrect, i.e., does not match the block size of the cipher {0}
net.gencat.ctti.canigo.services.lopd.exception.badpadding a particular padding mechanism is expected for the input data but the data is not padded properly {0}
net.gencat.ctti.canigo.services.lopd.exception.illegalaccess the currently executing method does not have access to the definition of the specified class({0}), field({1}, method or constructor
net.gencat.ctti.canigo.services.lopd.exception.invocationtarget exception thrown by an invoked method or constructor
net.gencat.ctti.canigo.services.lopd.exception.nosuchmethod getter method cannot be found
net.gencat.ctti.canigo.services.lopd.exception.illegalargument getter method has been passed an illegal or inappropriate argument

S'haurà de configurar aquests missatges amb el servei de internacionalització de Canigó perquè es mostrin amb el literal en l'idioma de l'aplicació.

Utilització del Servei

Tot seguit anem a presentar un exemple d'ús del servei de LOPD en una aplicació Canigó. Suposem que tenim un BO anomenat GestioDadesPacientBO que s'encarrega d'accedir i manipular les dades d'un pacient.
Suposem també que hi ha una taula anomenada PACIENT que conté les dades del pacient, i una classe que la mapeja a objecte anomenada Pacient. Afegim també una taula anomenada MALALTIES i la corresponent classe Malalties que te com a clau forana l'identificador del malalt.
El primer que s'ha de fer és determinar quines dades són sensibles i a quin nivell. Podem determinar que les dades del pacient seran de nivell bàsic, i les de les seves malalties de nivell alt.
Després es procedeix a configurar el servei. Per fer-ho s'ha de crear el fitxer canigo-services-lopd.xml amb el contingut:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 	<import resource="classpath:/spring/default-canigo-services-lopd.xml" />
	
 	<bean id="LOPDAttributesSource" class="net.gencat.ctti.canigo.services.lopd.definition.impl.LOPDAttributeSourceImpl">
 		<property name="LOPDAttributes">
 			<props>
 				<prop key="net.gencat.ctti.canigo.samples.prototip.model.Malalties.*">HIGH_LEVEL</prop>
 				<prop key="net.gencat.ctti.canigo.samples.prototip.model.Pacient.*">LOW_LEVEL</prop>
 			</props>
 		</property>
 	</bean>
	
</beans>

Un cop configurat el servei, es creen el proxy y el BO corresponents per la classe GestioDadesPacientBO:

<bean id="GestioDadesPacientBOTarget" class="net.gencat.ctti.canigo.samples.prototip.model.bo.impl.GestioDadesPacientBOImpl">
 		<property name="dao" ref="universalHibernateDAO"/>
 	</bean>	
	
 	<bean id="GestioDadesPacientBO" parent="baseLOPDProxy">
 			<property name="target"><ref bean="categoryBOTarget"/></property>
 	</bean>
    
    <bean id="baseLOPDProxy"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
 		<property name="transactionManager">
 			<ref local="transactionManager" />
 		</property>
 		<property name="target">
 			<bean class="java.lang.Object" />
 		</property>
 		<property name="preInterceptors">
 			<list>
 				<ref bean="preLOPDInterceptor"/>
 			</list>
 		</property>
 		<property name="postInterceptors">
 			<list>
 				<ref bean="postLOPDInterceptor"/>
 			</list>
 		</property>
 		<property name="transactionAttributes">
 			<props>
 				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
 				<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
 				<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
 				<prop key="store*">PROPAGATION_REQUIRED</prop>
 				<prop key="save*">PROPAGATION_REQUIRED</prop>
 				<prop key="delete*">PROPAGATION_REQUIRED</prop>
 			</props>
 		</property>
	</bean>

Com es pot apreciar, la principal diferencia en el baseLOPDProxy és el fer d'afegir un preInterceptor i un postInterceptor. Aquests corresponen als que porta el servei configurats per defecte que són, pel cas del nivell alt, el de registre d'accés i els d'encriptació i desencriptació de dades.
Un cop fet tot això, quan s'accedeixi a alguna funció del BO GestioDadesPacientBO que tingui com a paràmetre o com a dada de retorn alguna instància de la classe Malalties, es guardarà el registre de l'accés al log de l'aplicació. A més, si es tracta d'una funció que insereix o actualitza una dada l'encriptarà, i si es tracta de recuperar una dada de la mateixa la desencriptarà.

Apendix A. default-canigo-services.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="LOPDCipher" class="net.gencat.ctti.canigo.services.lopd.crypto.impl.BouncyCastleAESCipherImpl">
<property name="key" value="${lopd.secretkey}"/>
</bean>

<bean id="EncryptLOPDHandler" class="net.gencat.ctti.canigo.services.lopd.handler.impl.EncryptDataHandler">
<property name="loggingService" ref="loggingService"/>
<property name="cipher" ref="LOPDCipher"/>
</bean>
<bean id="DecryptLOPDHandler" class="net.gencat.ctti.canigo.services.lopd.handler.impl.DecryptDataHandler">
<property name="loggingService" ref="loggingService"/>
<property name="cipher" ref="LOPDCipher"/>
</bean>
<bean id="LogLOPDHandler" class="net.gencat.ctti.canigo.services.lopd.handler.impl.LoggingHandler">
<property name="loggingService" ref="loggingService"/>
</bean>

<bean id="LOPDInterceptor" class="net.gencat.ctti.canigo.services.lopd.interceptor.impl.LOPDInterceptorImpl" abstract="true">
<property name="LOPDAttributeSource" ref="LOPDAttributesSource"/>
</bean>

<bean id="preLOPDInterceptor" class="net.gencat.ctti.canigo.services.lopd.interceptor.impl.PreLOPDInterceptorImpl">
<property name="LOPDAttributeSource" ref="LOPDAttributesSource"/>
<property name="highLevelHandlers">
<list>
<ref bean="EncryptLOPDHandler" />
</list>
</property>
</bean>
<bean id="postLOPDInterceptor" class="net.gencat.ctti.canigo.services.lopd.interceptor.impl.PostLOPDInterceptorImpl">
<property name="LOPDAttributeSource" ref="LOPDAttributesSource"/>
<property name="highLevelHandlers">
<list>
<ref bean="LogLOPDHandler" />
<ref bean="DecryptLOPDHandler" />
</list>
</property>
</bean>
</beans>

Apendix B. AESKeyGen

Amb el servei, s'adjunta una classe executable Java que permet la generació de claus AES, que són les que fa servir el mateix pel xifratge de dades.
Un exemple d'utilització d'aquesta classe seria:

C:\>java -cp canigo-services-lopd-2.3.15.jar;bcprov-jdk15-140.jar  net.gencat.ctti.canigo.services.lopd.tools.AESKeyGen
Generating AES key....
Generated key is:
80a83554649f6554601fd23159d7f104
done

De la pantalla anterior es despren la necessitat de comptar amb els jars del servei de lopd i de bouncycastle per poder generar la clau AES. Després només cal copiar aquesta clau al fitxer de propietats lopd.properties.