Las normas expuestas son de obligado cumplimiento. La STIC podrá estudiar los casos excepcionales los cuales serán gestionados a través de los responsables del proyecto correspondiente y autorizados por el Área de Gobernanza de la STIC. Asimismo cualquier aspecto no recogido en estas normas deberá regirse en primera instancia por las guías técnicas correspondientes al esquema nacional de seguridad y esquema nacional de interoperabilidad según correspondencia y en su defecto a los marcos normativos y de desarrollo software establecidos por la Junta de Andalucía, debiendo ser puesto de manifiesto ante la STIC.
La STIC se reserva el derecho a la modificación de la norma sin previo aviso, tras lo cual, notificará del cambio a los actores implicados para su adopción inmediata según la planificación de cada proyecto.
En el caso de que algún actor considere conveniente y/o necesario el incumplimiento de alguna de las normas y/o recomendaciones, deberá aportar previamente la correspondiente justificación fehaciente documentada de la solución alternativa propuesta, así como toda aquella documentación que le sea requerida por la STIC para proceder a su validación técnica.
Contacto Arquitectura: l-arquitectura.stic@juntadeandalucia.es
Los cambios en la normativa vendrán acompañados de un registro de las modificaciones. De este modo se podrá realizar un seguimiento y consultar su evolución. Ordenándose de mas recientes a menos recientes, prestando especial cuidado a las cabezeras de la tablas dónde se indican las fechas de entrada en vigor y versión.
Con el objetivo de facilitar el cumplimiento de la normativa del SAS en cuanto auditoría se refiere, desde el área de gobernanza de la STIC se ha realizado un componente reutilizable que permita a los desarrolladores incorporar todo el sistema de auditorías en sus aplicaciones de forma rápida y estandarizada, minimizando el tiempo necesario que se requiere para realizar este proceso.
Como punto de partida, y tras analizar las diferentes alternativas ya existentes, se decide partir de una librería de código abierto ya existente que cubre parcialmente las necesidades existentes en la casa, de forma que desde la STIC se ha realizado una ramificación propia de este software para ser adaptado completamente a los requerimientos de auditorías exigidos por la organización.
La librería desarrollada cuanta con las siguientes características:
La librería original ha sido adaptada a la normativa vigente en el SAS, por lo que está diseñada para ser utilizada en proyectos que sean ejecutados bajo el paraguas de Weblogic 12.1.3. En el siguiente enlace puede consultarse el detalle de las APIs que ofrece esta versión de Weblogic: http://docs.oracle.com/middleware/1213/wls/NOTES/whatsnew.htm#BGGGHCJD
La librería desarrollada se encuentra ubicada en el artifactory corporativo del SAS, estando preparada para ser usada por cualquier usuario que lo desee. Por tanto, para hacer uso de la libería bastará con incorporar librería en pom.xml
<dependency> <groupId>es.ja.csalud.sas.componentescomunes.audit4j-extension</groupId> <artifactId>audit4j-sas</artifactId> <version>1.0.3.1</version> </dependency>
(*) Antes de hacer uso de la librería, se recomienda consultar en artifactory la última versión disponisble (http://calidad.sas.junta-andalucia.es/artifactory/sas-internal/es/ja/csalud/sas/componentescomunes/).
Una vez ha sido incorporada la librería en nuestro proyecto, es necesario realizar una pequeña configuración que permita ajustar el funcionamiento del sistema a nuestras necesidades.
El primer paso para configurar nuestro proyecto será crear un archivo YAML llamado "audit4j.conf.yaml" en el CLASSPATH del proyecto, el cual será típicamente la ruta "src/main/resources" para un proyecto tipo maven.
!Configuration # Obligatorio # Listado de Handlers. Pueden ser uno o más. handlers: #- !org.audit4j.core.handler.ConsoleAuditHandler {} #- !org.audit4j.core.handler.file.FileAuditHandler {} #- !org.audit4j.handler.db.DatabaseAuditHandler{} - !org.audit4j.jms.handler.JmsAuditHandler {} # Configuración de layouts. Sólo necesario para algunos handlers, por ejemplo Console o File # Dejar SimpleLayout si no se va a usar los handlers anteriormente indicados layout: !org.audit4j.core.layout.SimpleLayout {} # Configuración de la clase de la que se recupera información del usuario logado. # La implementación por defecto DummyMetaData devuele un valores genéricos y constantes metaData: !org.audit4j.core.DummyMetaData {} # Comandos especiales # -metadata: Sincronía, "sync" or "async" (Se recomienda usar "async") # -annotationTransformer: Clase encargada de procesar las anotaciones # + El transformer por defecto auditará todos los parámetros de entradas del método auditado # + StrictAnnotationTransformer: Auditará SOLO los parámetros marcados con la anotación @AuditField # + ManualAnnotationTransformer: Auditará en función de los parámetros indicados en la anotación @Audit # o bien en lo indicado en los XML de configuración avanzada commands: -metadata=async -annotationTransformer=org.audit4j.annotation.transformer.ManualAnnotationTransformer # Propiedades adicionales properties: # Paquete en el se va a rastrear las anotaciones avanzadas de auditorías (no es necesario si se utilizan XMLs) audit_fields_package: es.ja.csalud.sas.webexample # Fichero XML del que se va a leer la información a auditar (no es necesario si se utilizan Anotaciones) audit_fields_xml: auditConfig.xml # Número máximo de hilos concurrentes que podrán procesar eventos de auditorías (Valor por defecto 20, # poner un valor mayor threads_pool_size: 20 # Nombres de la factoría y cola JMS a utilizar en caso de usar el handler JmsAuditHandler jms_factory: ConnectionFactory-ResponsePool jms_queue: Queue-ResponsePool
Una vez disponemos del módulo configurado, será necesario inicializar el motor al iniciar nuestro servidor. Existen diferentes formas de conseguir que un proceso se ejecute al inicializar un servidor. A modo de ejemplo, en las pruebas realizadas por el área de arquitectura se ha hecho uso de las las anotaciones @Startup y @Singleton:
@Singleton @Startup public class AuditConfig { @PostConstruct protected void init() { // Inicialización del motor de auditoría AuditManager.start(); // Carga del mapping configurado mediante anotaciones avanzadas o XML AuditFieldMapperManager.start(); } }
Una vez se inicie nuestro servidor, se mostrará por consola un mensaje similar al siguiente:
dic 01, 2016 11:14:03 AM org.audit4j.core.util.Log info INFORMACIÓN: Audit4j:INFO Audit4j initialized. Total time: 124ms dic 01, 2016 11:14:03 AM org.audit4j.core.util.Log info INFORMACIÓN: Audit4j:INFO Loading Audit field mapping
El modo más básico de utilizar el motor de auditoría es creando un objeto de tipo AuditEvent e insertarlo en la auditoría. En el siguiente ejemplo puede verse como crear el objeto e invocar al motor de auditoría. Este modo puede utilizarse en cualquier parte de nuestro código:
// Creación del evento AuditEvent event = new AuditEvent(); event.setObject("Episodio"); // Objeto auditado event.setAction("Cancelar"); // Acción a realizar // Listado de campos a auditar // Los campos con ID "nuhsa", "episodio" y "unidad" se mapearán automáticamente // con las columnas de mismo nombre en la tabla de adutoría. // El resto de campos se almacenarán como información adicional event.addField(new Field("nuhsa", pIn.getNuhsa())); event.addField(new Field("episodio", "123456")); event.addField(new Field("unidad", "1111")); event.addField(new Field("apellido1", pIn.getApellido1())); // Resultado: 0 Correcto, 1 Incorrecto event.setResultCode(new Random().nextInt() % 2); // Datos opcionales. Si no se indican se recuperarán del MetaData configurado event.setActor("jparriazap"); event.setActorProfile("medico"); event.setActorService("Medicina Interna"); event.setOrigin("MPA"); // Llamada DIRECTA al motor de auditoría AuditManager.getInstance().audit(event);
La auditoría por anotaciones permiten configurar puntos de auditoría fácilmente sin necesidad de añadir código adicional a nuestros proyectos. Dentro de la auditoría por anotaciones nos encontramos con varios modos de funcionmiento de la librería, siendo el modo Manual el que se propone desde el área de gobernanza como el más indicado para las necesidades del SAS.
Es imporante destacar que por el propio funcionamiento de las anotaciones y los insterceptores de Java EE, este mecanismo funciona solamente cuando nos encontremos en un contexto CDI.
hay que añadir tambien en el bean.xml el interceptor de auditoria para que funcionen las anotaciones:
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <interceptors> <class org.audit4j.integration.cdi.AuditInterceptor </class> </interceptors> </beans>
Las anotaciones disponibles son las siguientes:
@Audit: Es la anotación principal que indica que un método debe ser auditado. Permite las siguientes propiedades:
@AuditField: Es aplicable tanto a parámetros de un método como a atributos de una clase. Tiene las siguientes propiedades:
@DeIdentify: Se utiliza para anonimizar parámetros sensibles que desean ser auditados. Tiene las siguientes propiedades:
@IgnoreAudit: Indica que un parámetro de un método debe ser ignorado. Sólo tiene sentido usar esta anotación en la auditoría por defecto, donde se auditan todos los parámetros de un método menos los marcados con esta anotación.
Modo de funcionar por defecto, es el que aplica si no se indica el comando annotationTransformer en el fichero de configuración.
En este modo, se auditan todos los parámetros de entrada de un método a excepción de los marcados como @IgnoreAudit.
public class Paciente { private long id; private String nuhsa; private String nombre; @AuditIgnore private String apellido1; private String apellido2; ... } @Stateless public class Pacientes { @Audit ( object = "Paciente", action = "Buscar" ) public Paciente buscaPacienteDefault(Paciente pacienteIn, @IgnoreAudit int edad, boolean activo) { ... } }
En este ejemplo, todos los objetos que inyecten el servicio "Pacientes" e invoque al método "buscaPacienteStrict" generará un registro en la auditoría indicando que se ha actuado sobre el objeto "Paciente", realizando la acción "Buscar" y se auditarán todos los parámetros de entrada recursivamente (auditando también todos los atributos de los objetos complejos no marcados con @IgnoreAudit) salvo el parametro "edad" por estar marcado con la anotación @IgnoreAudit
El modo estricto audita sólo aquellos parámetros y atributos marcados a conciencia con la anotación @AuditField. En el caso de que uno de los parámetros de entradas no sea de tipo primitivo Java, el motor de auditoría recorrerá recursivamente los atributos internos y auditará sólo aquellos que estén marcados como @AuditField.
Para hacer uso de este módo es necesario indicar el comando annotationTransformer con el siguiente valor: org.audit4j.annotation.transformer.StrictAnnotationTransformer
public class Paciente { private long id; @AuditField(field="nuhsa") private String nuhsa; @AuditField(field="nombre") private String nombre; private String apellido1; private String apellido2; ... } @Stateless public class Pacientes { @Audit ( object = "Paciente", action = "Buscar" ) public Paciente buscaPacienteStrict(@AuditField(field = "paciente") Paciente pacienteIn, @AuditField(field = "edad") int edad, boolean activo) { ... } }
En este ejemplo, todos los objetos que inyecten el servicio "Pacientes" e invoque al método "buscaPacienteStrict" generará un registro en la auditoría indicando que se ha actuado sobre el objeto "Paciente", realizando la acción "Buscar" y se auditarán los atributos "paciente.nuhsa", "paciente.nombre" y el segundo parámetro (edad).
El modo manual permite realizar toda la configuración a auditar directamente sobre la anotación padre @Audit o en ficheros de configuración XML. Al igual que en el modo estricto, auditará sólo aquellos parámetros y atributos marcados como auditables.
Para hacer uso de este módo es necesario indicar el comando annotationTransformer con el siguiente valor: org.audit4j.annotation.transformer.ManualAnnotationTransformer
Desde el área de gobernanza se aconseja usar este método para conseguir así un código resultante más limpio.
Dentro de este método nos encontramos dos formas utilizarlo.
Permite indicar toda la configuración de la auditoría en la misma anotación @Audit:
public class Paciente { private long id; private String nuhsa; private String nombre; private String apellido1; private String apellido2; ... } @Stateless public class Pacientes { @Audit ( object = "Paciente", action = "Buscar", fields = { @AuditField(field="nuhsa", fieldPath="[0].nuhsa"), @AuditField(field="id", fieldPath="[0].id"), @AuditField(field="apellido1", fieldPath="[0].apellido1"), @AuditField(field="edad", fieldPath="[1]"), @AuditField(field="apellido2", fieldPath="result.apellido2") } ) public Paciente buscaPacienteAnotacion(Paciente pacienteIn, int edad, boolean activo) { ... } }
En este ejemplo, todos los objetos que inyecten el servicio "Pacientes" e invoque al método "buscaPacienteAnotacion" generará un registro en la auditoría indicando que se ha actuado sobre el objeto "Paciente", realizando la acción "Buscar" y se auditarán los atributos "nuhsa", "id" y "apellido1" del primer parámetro de entrada (pacienteIn), el segundo parámetro (edad) y del objeto devuelto como resultado, el atributo "apellido2"
Permite indicar toda la configuración de la auditoría en un fichero XML, centralizando toda la configuración de auditoría de todo el proyecto completo en un sólo fichero de configuración. En este caso, a nivel de método sólo será necesario marcarlo como @Audit y no será necesario especificar más propiedades:
public class Paciente { private long id; private String nuhsa; private String nombre; private String apellido1; private String apellido2; ... } @Stateless public class Pacientes { @Audit public Paciente buscaPacienteXML(Paciente pacienteIn, int edad, boolean activo) { ... } }
<?xml version="1.0" encoding="UTF-8"?> <auditConfiguration> <method>...</method> <method path="es.ja.csalud.sas.webexample.service.boundary.Pacientes.buscaPacienteXML" object="Paciente" action="Buscar"> <auditField field="nuhsa" fieldPath="[0].nuhsa"/> <auditField field="id" fieldPath="[0].id"/> <auditField field="apellido1" fieldPath="[0].apellido1"/> <auditField field="edad" fieldPath="[1]"/> <auditField field="apellido2" fieldPath="result.apellido2"/> </method> <method>...</method> <method>...</method> </auditConfiguration>
En este ejemplo, todos los objetos que inyecten el servicio "Pacientes" e invoque al método "buscaPacienteXML" generará un registro en la auditoría indicando que se ha actuado sobre el objeto "Paciente", realizando la acción "Buscar" y se auditarán los atributos "nuhsa", "id" y "apellido1" del primer parámetro de entrada (pacienteIn), el segundo parámetro (edad) y del objeto devuelto como resultado, el atributo "apellido2"
Como puede verse en el apartado "¿Qué se debe auditar en el SAS?" de la normativa de auditoría, existen una serie de campos básicos que deben ser auditados, igualmente se reserva un espacio adicional para otros campos no básicos que también deban ser auditados.
Para poder especificar qué campos corresponden con cada uno de estos campos básicos se han definido un patrón de etiquetado que debe ser seguido para el buen funcionamiento del sistema. De esta forma, se definen los siguientes elmentos (No se diferencia entre mayúsculas y minúsculas):
Mención especial requiere los campos Operador, Operador_Perfil y Operador_Unidad, ya que estos campos son normalmente recuperados de la implementación de la interfaz MetaData propia de cada producto. Pero pueden existir casos en los que la aplicación no tenga sesión (Aplicaciones REST) en donde no sea posible realizar una implementación de MetaData para recuperar datos del contexto. En estos casos esta información deberá ser configurada manualmente en cada evento a auditar.
Por orden de prioridades, el motor de auditoría mirará en primer lugar si se ha configurado un valor específico para un evento, en caso de no existir lo buscará en la implementación de la clase MetaData y en caso de no existir insertará un valor por defecto.
@Stateless public class Pacientes { @Audit ( object = "Paciente", action = "Buscar", fields = { @AuditField(field="operador", fieldPath="[0].login"), @AuditField(field="operador_perfil", fieldPath="[0].perfil"), @AuditField(field="nuhsa", fieldPath="[1].nuhsa"), @AuditField(field="id", fieldPath="[1].id"), @AuditField(field="apellido1", fieldPath="[1].apellido1"), @AuditField(field="apellido2", fieldPath="[1].apellido2"), @AuditField(field="edad", fieldPath="[2]") } ) public Paciente buscaPaciente(Usuario user, Paciente pacienteIn, int edad, boolean activo) { ... } }
En este ejemplo vemos como se ha configurado para que los campos operador y operador_perfil sean cargados directamente del primer parámetro de la función auditada. En el caso de la unidad del operador, al no estar configurado en el evento, se recuperará de la implementación de MetaData que se haya realizado y en caso de no existir el registro de auditoría se creará con el valor por defecto ("Default User Service")