Java tutorial
/* Copyright (C) 2007 Flix Garca Borrego (borrego at gmail.com) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package org.viafirma.nucleo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import java.security.Security; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Properties; import javax.mail.MessagingException; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.parsers.ParserConfigurationException; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.lang.time.DateUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.MultiPartEmail; import org.apache.xml.security.keys.keyresolver.KeyResolverException; import org.apache.xml.security.signature.XMLSignature; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.viafirma.cliente.firma.TypeFile; import org.viafirma.cliente.firma.TypeFormatSign; import org.viafirma.cliente.util.ConfigUtil; import org.viafirma.cliente.vo.FirmaInfoViafirma; import org.viafirma.conector.ConectorFirmaRMI; import org.viafirma.excepciones.CodigoError; import org.viafirma.excepciones.ExcepcionCertificadoNoEncontrado; import org.viafirma.excepciones.ExcepcionErrorInterno; import org.viafirma.nucleo.X509.CertificadoGenericoFactory; import org.viafirma.nucleo.autenticacion.AutenticacionBridge; import org.viafirma.nucleo.custodia.Custodia; import org.viafirma.nucleo.firma.FirmaBridge; import org.viafirma.nucleo.inicio.SecurityProvidersUtils; import org.viafirma.nucleo.validacion.ValidadorHandler; import org.viafirma.util.Constantes; import org.viafirma.util.FaceletsUtil; import org.viafirma.util.QRCodeUtil; import org.viafirma.util.SendMailUtil; import org.viafirma.util.XmlSignUtil; import org.viafirma.vo.CertificadoGenerico; import org.viafirma.vo.Documento; import org.w3c.dom.Document; import com.viavansi.framework.core.servlet.StartupServletContextListener; import com.viavansi.framework.core.util.BeanUtil; import com.viavansi.framework.core.util.CadenaUtilities; import com.viavansi.framework.tools.repositorio.vo.DocumentVO; /** * Nucleo de la plataforma de autenticacin y firma. Sus funciones principales * son : * * <pre> * -Inicializar el sistema. init() * -Iniciar el proceso de autenticacin redireccionando al AutenticacionBridge. iniciarAutenticacion(). * -Procesar el resultado de la autenticacin, validando las crls,etc .. finAutenticacion() * -Generar los comprobantes de firma en formato QR Code. * -Delegar en el sistema de Custodia para el almacen de firmas digitales. * </pre> * * @author Felix Garcia Borrego (borrego at gmail.com) * @author Alexis Castilla Armero <Pencerval at Gmail.com> */ public class Nucleo extends StartupServletContextListener { // logger del nucleo private static Log log = LogFactory.getLog(Nucleo.class); /** * Cache con los certificados gestionados por el Nucleo. Almacena los * certificados temporalmente mientras estos se estan procesando */ private Cache cacheCertificados; /** * Cache con los ficheros que actualmente tiene retenidos el Nucleo a la * espera de que sean firmados. * */ private Cache cacheDocumentToSign; /** * Nombre de la variable en la que se almacena el identificador de * autenticacin. * */ public static String SESSION_ID = "sessionID"; /** * El tiempo maximo que el Nucleo mantiene un certificado mientras este es * procesado en memoria son 2 minutos. */ private int TIEMPO_VIDA_CERTIFICADO = 2 * 60; /** * El tiempo maximo que el Nucleo mantiene un documento en espera de que * este sea firmado */ private int TIEMPO_VIDA_DOCUMENT_TO_SIGN = 10 * 60; /** * Identificador de de los certificados que son reconocidos por viafirma * Todos los certificados reconocidos por viafirma deben empezar por * viafirma_ */ public static final String IDENTIFICADOR_CERTIFICADO_VIAFIRMA_KEYSTORE = "viafirma"; /** * Validador de certificados utilizado por el nucleo para determinar si un * certificado es vlido o no. */ private ValidadorHandler validador; /** * Registro rmi en el que se publican los servicios via rmi del ncleo. */ Registry rmiRegistry; /** * Url pblica para la verificacin de documentos. */ public String URL_PUBLIC_VERIFICATION; /** * Inicializa el nucleo, y este a su vez inicializa todos los mdulos que * dependen de el * */ @Override public void init(ServletContext context) { singleton = this; // 1.- inicializamos el sistema de criptografa // Eliminamos el proveedor para evitar que se solapen si ya existia uno. //Security.removeProvider(new BouncyCastleProvider().getName()); //Security.addProvider(new BouncyCastleProvider()); //log.info("Lista de proveedores disponible:" + Arrays.asList(Security.getProviders())); // 1.- Inicializamos los proveedores criptograficos SecurityProvidersUtils.initProviders(); org.apache.xml.security.Init.init(); // inicializa el sistema de cache para mantener los certificados CacheManager manager = CacheManager.getInstance(); cacheCertificados = new Cache("cacheCertificadosEnUso", 200, false, false, TIEMPO_VIDA_CERTIFICADO, TIEMPO_VIDA_CERTIFICADO); manager.addCache(cacheCertificados); log.debug("Inicializada cache de certificados."); cacheDocumentToSign = new Cache("cacheDocumentoToSign", 100, true, false, TIEMPO_VIDA_DOCUMENT_TO_SIGN, TIEMPO_VIDA_DOCUMENT_TO_SIGN); manager.addCache(cacheDocumentToSign); log.debug("Inicializada cache documentos a firmar ."); // 2.- inicializo el servicio RMI. // creamos un registro propio programticamente // en lugar de utilizar el registro JNDI del servidor de aplicaciones o // el comando rmiregistry para aislar nuestra aplicacin de // incompatibilidades // entre diferentes servidores de aplicaciones. try { rmiRegistry = LocateRegistry.createRegistry(Constantes.PORT_RMI); // creamos la instancia del Servidor ConectorFirmaRMI serverRMI = new ConectorFirmaRMI(); // publicamos el servidor en el registro rmiRegistry.bind(Constantes.NOMBRE_CONECOR_RMI_PUBLICADO, serverRMI); log.info("Avtivado registro RMI. Puerto: " + Constantes.PORT_RMI + ", nombre del servicio: " + Constantes.NOMBRE_CONECOR_RMI_PUBLICADO); // Publicamos el servicio tambien en web } catch (RemoteException e) { // No se puede activar el servicio RMI. log.fatal("No se puede activar el servicio RMI " + e.getMessage(), e); } catch (AlreadyBoundException e) { // El puerto ya esta en uso. log.fatal("El puesto " + Constantes.PORT_RMI + " ya esta en uso por otra aplicacin. No se puede activar el servicio de firma", e); } Properties properties = ConfigUtil.getInstance().readConfigPropertes(); // 3.- iniciamos el sistema de custodia de docuemtos Custodia.init(properties); // 4.- iniciamos las erramientas de QRCode QRCodeUtil.init(properties); // 5.- inicializo el envio de Email. SendMailUtil.init(properties); // Configuracin del sistema de validacin de CRLs. Por defecto la // validacin esta activada. String tempValidacion = (String) properties.get(Constantes.PARAM_VALIDACION_ONLINE); boolean validacionOnline = tempValidacion == null ? true : new Boolean(tempValidacion); ValidadorHandler.init(validacionOnline, properties); validador = ValidadorHandler.getCurrentInstance(); log.debug("Inicializado Validador de certificados. Validacin online en: " + validacionOnline); // Metemos en el contexto de aplicacin todos los parametros de // configuracin for (Object key : properties.keySet()) { context.setAttribute((String) key, properties.get(key)); } // Recuperamos la url pblica: URL_PUBLIC_VERIFICATION = properties.getProperty(Constantes.PARAM_URL_APLICACION) + Constantes.PATH_VERIFICACION; log.info("Nucleo Inicializado. "); } /** * Recupera una instancia del ncleo. Si el nucleo no se ha inicializado con * exito lanza una excepcin */ public static org.viafirma.nucleo.Nucleo getInstance() { if (singleton == null) { log.fatal( "Ncleo no inicializado correctamente, imposible recuperar la instancia. Revise la secuencia de arranque del contexto"); throw new IllegalStateException("El ncleo no esta inicializado"); } else { return singleton; } } /** * Este motodo es invocado por los conectores cuando desean iniciar el * proceso de autenticacin para el usuario que esta haciendo uso del * conector. * * @param codAplicacion * Cdigo de la aplicacin utilizada( si no se esta utilizando el * protocolo openID) * @param tipo * Indica el tipo de autenticacin que va a utilizar el Ncleo( * EJ: openID * @throws ExcepcionNoEncontrado * La aplicacin indicada por el conector no existe * @throws ExcepcionErrorInterno */ public void iniciarAutenticacion(TipoCliente tipo, HttpServletRequest request, HttpServletResponse response) throws ExcepcionErrorInterno { // recuperamos al bridge que estamos utilizando segun el tipo de // autenticacin a realizar Factory factoria = Factory.getInstance(); AutenticacionBridge autenticacionBridge = factoria.getAuntenticacionBridget(tipo); // delegamos el bridget( Handler) para que relize el proceso de // autenticacin // una vez que este termine de autenticar al usuario retornara invocara // al metodo finAutenticacin autenticacionBridge.generarSolicitudCertificado(request, response); } /** * Este metodo es invocado por el bridget especifico cuando este ha * terminado de realizar la autenticacin. El nucleo deberar validar el * certificado, auditar la operacin y retornar los datos del certificado al * conector para que este retorne los datos al usuario. * * @param certificadoX509 * Certificado del usuario */ public void finAutenticacion(String sessionID, HttpServletRequest request, HttpServletResponse response) { // recuperamos el certificado X509Certificate certificadoX509 = getCertificadoCacheado(sessionID); if (certificadoX509 == null) { log.info("El certificado no se encuentra en sessin."); request.setAttribute("codError", org.viafirma.cliente.exception.CodigoError.ERROR_PROTOCOLO_FIRMA); FaceletsUtil.forward(request, response, Constantes.URI_ERROR_FIRMA); return; } // el siguiente paso es validar el certificado con las CRLs. CodigoError codigo = validador.validar(certificadoX509); // CodigoError. // OK_CERTIFICADO_VALIDADO // ; if (codigo == CodigoError.OK_CERTIFICADO_VALIDADO) { log.info("El certificado ha sido validado, redireccion a la aplicacin llamante"); try { CertificadoGenerico certificado = CertificadoGenericoFactory.getInstance().generar(certificadoX509); // invoco al conector Utilizado para que retorne la respuesta al // usuario // por ahora el conector sera OpenIDServlet request.setAttribute("CodigoError", codigo); request.setAttribute("certificado", certificado); // TODO colocar un getConectorutilizado y utilizar un metoro // redirectMe del conector. request.getRequestDispatcher("/conectorAutenticacionOpenId").forward(request, response); // response.sendRedirect(aplicacion.getUrlRetorno()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ServletException e) { // TODO Auto-generated catch block e.printStackTrace(); } } else { log.info("El certificado no ha sido validado, redireccion a una pagina de error de validacin."); request.setAttribute("codError", codigo); FaceletsUtil.forward(request, response, Constantes.URI_ERROR_AUTENTICACION); } } // ********************************************** // Acciones relacionadas con el proceso de Firma // ********************************************** /** * Almacena un fichero en la cache de firma y le asigna un identificador. El * fichero permanecera unos minutos en la cache a la espera de que el * usuario proceda a su firma definitiva * * @param documentToSign */ public String prepareSign(Documento documentToSign) { // generamos el identificador que tendra el documento. String key = generarIdentificador(); documentToSign.setId(key); // almacenamos el documento en la cache cacheDocumentToSign.put(new Element(key, documentToSign)); log.info("Nuevo documento pendiente de firma " + documentToSign); return key; } /** * Este motodo es invocado por los conectores cuando desean iniciar el * proceso de firma para el usuario que esta haciendo uso del * * @param tipo * Indica el tipo de autenticacin que va a utilizar el Ncleo( * EJ: openID * @throws ExcepcionNoEncontrado * La aplicacin indicada por el conector no existe * @throws ExcepcionErrorInterno */ public void iniciarFirma(TipoCliente tipo, String idFirma, HttpServletRequest request, HttpServletResponse response) throws ExcepcionErrorInterno { // recuperamos al bridge que estamos utilizando segun el tipo de // autenticacin a realizar Factory factoria = Factory.getInstance(); // recupero el documento Documento documento = getDocumentoCacheado(idFirma); if (documento == null || documento.getDatos() == null) { log.warn("El fichero indicado est vaco"); throw new ExcepcionErrorInterno(CodigoError.ERROR_FILE_EMPTY); } FirmaBridge firmaBridge = factoria.getFirmaBridget(tipo); // delegamos el bridget( Handler) para que relize el proceso de firma // una vez que este termine de autenticar al usuario retornara invocara // al metodo finAutenticacin // TODO controlar excepciones y enviar a pgina de error. firmaBridge.generarSolicitudFirma(documento, request, response); } /** * Este metodo es invocado por el bridget especifico cuando este ha * terminado de realizar la firma. El nucleo deberar validar el certificado, * almacenar el resultado de la firma, auditar la operacin y retornar los * datos de la operacin al usuario. * * @param certificadoX509 * Certificado del usuario */ public void finFirma(String sessionID, String idFirma, HttpServletRequest request, HttpServletResponse response) { // obtenemos el certificado X509Certificate certificadoX509 = getCertificadoCacheado(sessionID); if (certificadoX509 == null) { log.info("El certificado no se encuentra en sessin."); request.setAttribute("codError", org.viafirma.cliente.exception.CodigoError.ERROR_PROTOCOLO_FIRMA); FaceletsUtil.forward(request, response, Constantes.URI_ERROR_FIRMA); return; } // obtenemos el documento XML firmado por el usuario Document xmlSignedDocument = getXMLDocument(sessionID); // Obtenemos el documento original que ha sido firmadofirmado. Documento documento = getDocumentoCacheado(idFirma); // eliminamos el documento de la cache removeDocumentoCacheado(idFirma); removeDocumentoCacheado(sessionID); // el siguiente paso es validar el certificado con las CRLs. CodigoError codigo = validador.validar(certificadoX509);// CodigoError. // OK_CERTIFICADO_VALIDADO // ; if (codigo == CodigoError.OK_CERTIFICADO_VALIDADO) { log.info("El certificado utilizado es correcto. Custodiamos el documento"); try { CertificadoGenerico certificado = CertificadoGenericoFactory.getInstance().generar(certificadoX509); // Custodiamos el documento Custodia custodia = Custodia.getInstance(); String newIdfirmaCustodia = custodia.custodiar(idFirma, xmlSignedDocument, documento.getTypeFormatSign()); log.info("Identificador de custodia asignado al documento firmado: " + newIdfirmaCustodia); // invoco al conector Utilizado para que retorne la respuesta al // usuario // por ahora el conector sera OpenIDServlet request.setAttribute("CodigoError", codigo); request.setAttribute("certificado", certificado); request.setAttribute("newIdfirmaCustodia", newIdfirmaCustodia); // TODO colocar un getConectorutilizado y utilizar un metoro // redirectMe del conector. request.getRequestDispatcher("/conectorFirmaOpenId").forward(request, response); // response.sendRedirect(aplicacion.getUrlRetorno()); } catch (IOException e) { // TODO Mejorar el control de excepciones e.printStackTrace(); } catch (ServletException e) { // TODO Mejorar el control de excepciones e.printStackTrace(); } catch (ExcepcionErrorInterno e) { log.fatal("El sistema de custodia no esta disponible en este momento", e); log.info("El certificado no ha sido validado, redireccion a una pagina de error de validacin."); request.setAttribute("codError", e.getCodError()); FaceletsUtil.forward(request, response, Constantes.URI_ERROR_FIRMA); } } else { log.info("El certificado no ha sido validado, redireccion a una pagina de error de validacin." + codigo); request.setAttribute("codError", codigo); FaceletsUtil.forward(request, response, Constantes.URI_ERROR_AUTENTICACION); } } /** * Firma los datos indicados con el certificado * * @param certificadoX509 * Certificado del usuario * @throws ExcepcionErrorInterno * @throws ExcepcionCertificadoNoEncontrado * @throws ParserConfigurationException */ public String signByServer(Documento documento, String alias, String password) throws ExcepcionErrorInterno, ExcepcionCertificadoNoEncontrado, ParserConfigurationException { // generamos el XML signature de los datos a firmar Document xmlDocument; if (documento.getTypeFormatSign().equals(TypeFormatSign.XMLSIG_ENVELOPING)) { xmlDocument = XmlSignUtil.getInstance().signDocument(documento, alias, password); // Generamos un identificador de firma al documento String idFirma = generarIdentificador(); // Custodiamos el documento Custodia custodia = Custodia.getInstance(); String newIdfirmaCustodia = custodia.custodiar(idFirma, xmlDocument, documento.getTypeFormatSign()); log.info("Identificador de custodia asignado al documento firmado por el servidor: " + newIdfirmaCustodia); // retornamos el identificador de custodia asignado return newIdfirmaCustodia; } else if (documento.getTypeFormatSign().equals(TypeFormatSign.XADES_EPES_ENVELOPED)) { throw new UnsupportedOperationException( "Esta operacin no esta soportada o implementada en la versin Viafirma GPL/Estandar"); } else { log.error("Formato de firma no soportado"); return null; } } /** * Recupera el documento custodiado con el identificador indicado. * * @param idDocumento * Identificador del documento custodiado * @return Documento custodiado * @throws ExcepcionErrorInterno * No se ha podido recuperar el documento custodiado. */ public Documento getDocumentoCustodiado(String idDocumento) throws ExcepcionErrorInterno { try { // recuperamos el documento custodiado. Custodia custodia = Custodia.getInstance(); Document xmlSig = custodia.recuperar(idDocumento); // Recupero el tipo de formato de firma utilizado. Documento documento = XmlSignUtil.getInstance().getDocument(xmlSig, idDocumento); if (log.isDebugEnabled()) log.debug("Recuperado el documento " + documento.getNombre()); return documento; } catch (ExcepcionErrorInterno e) { throw e; } catch (Exception e) { log.fatal("No se recuperar el documento custodiado: " + idDocumento, e); throw new ExcepcionErrorInterno(CodigoError.ERROR_INTERNO, e); } } /** * Comprueba que el documento indicado conincide con el documento custodiado * y es este a su vez es vlido * * @param originalData * @param id * @return */ public FirmaInfoViafirma checkOrignalDocumentSigned(byte[] originalData, String id) { FirmaInfoViafirma info = new FirmaInfoViafirma(); // Por defecto o si hay algun problema es invlido. info.setValid(false); try { // recuperamos el xmlSignature custodiado Document documento = Custodia.getInstance().recuperar(id); // TODO, permitir la recuperacin de todos los firmantes XMLSignature xmlSig = XmlSignUtil.getInstance().getXMLSignatureFormDocument(documento).get(0); CertificadoGenerico datosCertificado = CertificadoGenericoFactory.getInstance() .generar(xmlSig.getKeyInfo().getX509Certificate()); // Volcamos los datos del certificado generico sobre los datos de // firma info.setCaName(datosCertificado.getCa()); info.setProperties(info.getProperties()); info.setNumberUserId(datosCertificado.getNumberUserId()); info.setFirstName(datosCertificado.getNombre()); info.setLastName(datosCertificado.getApellido1()); info.setSignId(id); // Validamos el hash. boolean isValid = ValidadorHandler.getCurrentInstance().checkHash(originalData, id, xmlSig); info.setValid(isValid); } catch (ExcepcionErrorInterno e) { log.warn(e.getMessage()); info.setMessage(e.getMessage()); } catch (KeyResolverException e) { log.warn(e.getMessage()); info.setMessage(e.getMessage()); } return info; } /** * Retorna la metainformacin del usuario asociada al documento custodiado * con el identificador indicado. * * @param CodFirma * @return * @throws ExcepcionErrorInterno */ public Map<String, Object> getInfo(String codFirma) throws ExcepcionErrorInterno { // recuperamos el xmlSignature custodiado Object[] arrayDatos = Custodia.getInstance().recuperarMoreInfo(codFirma); Document documento = (Document) arrayDatos[1]; // TODO, permitir la recuperacin de todos los firmantes XMLSignature xmlSig = XmlSignUtil.getInstance().getXMLSignatureFormDocument(documento).get(0); try { CertificadoGenerico certificado = CertificadoGenericoFactory.getInstance() .generar(xmlSig.getKeyInfo().getX509Certificate()); Map<String, Object> datos = BeanUtil.getCurrentInstance().beanToMap(certificado); DocumentVO documentVO = (DocumentVO) arrayDatos[0]; datos.put(Constantes.FECHA, documentVO.getDateCreation().toString()); return datos; } catch (Exception e) { log.warn(e.getMessage()); throw new ExcepcionErrorInterno(CodigoError.ERROR_CUSTODIA); } } /** * Enva un email firmado al destinatario. * * @param texto * Texto del email * @param textoHtml * Versin HTML del email * @param datosAdjunto * Fichero adjunto si existe. * @param toUser * Usuario destino * @param alias * @param password * @throws ExcepcionErrorInterno * No se ha podido enviar el email. */ public void sendSignMailByServer(String subject, String mailTo, String texto, String htmlTexto, String alias, String password) throws ExcepcionErrorInterno { // Preparamos el envio MultiPartEmail mail; try { mail = SendMailUtil.getCurrentInstance().buildMessage(subject, mailTo, texto, htmlTexto, alias, password); // mail.setDebug(true); String id = mail.send(); if (log.isDebugEnabled()) { log.debug("Nuevo email enviado, con el identificador: " + id); mail.getMimeMessage().writeTo(System.out); } } catch (ExcepcionErrorInterno e) { log.warn(e.getMessage()); throw new ExcepcionErrorInterno(CodigoError.ERROR_SEND_MAIL, e.getMessage(), e); } catch (ExcepcionCertificadoNoEncontrado e) { log.warn(e.getMessage()); throw new ExcepcionErrorInterno(CodigoError.ERROR_SEND_MAIL, e.getMessage(), e); } catch (EmailException e) { log.warn(e.getMessage()); throw new ExcepcionErrorInterno(CodigoError.ERROR_SEND_MAIL, e.getMessage(), e); } catch (IOException e) { log.warn(e.getMessage()); throw new ExcepcionErrorInterno(CodigoError.ERROR_SEND_MAIL, e.getMessage(), e); } catch (MessagingException e) { log.warn(e.getMessage()); throw new ExcepcionErrorInterno(CodigoError.ERROR_SEND_MAIL, e.getMessage(), e); } } /** * Generamos un pdf ( para descarga) con el contenido original firmado + el * cdigo QR. * * @param codFirma * @param texto * . Si el texto es null se utiliza como texto el nombre del * certificado firmante. * @return * @throws ExcepcionErrorInterno */ public byte[] buildInfoQRBarCode(String codFirma, String texto, String textoQR, boolean isPdf) throws ExcepcionErrorInterno { ByteArrayOutputStream out = new ByteArrayOutputStream(); try { // recuperamos el xmlSignature custodiado Document xmlDocument = Custodia.getInstance().recuperar(codFirma); // TODO Soporte de elementos multifirmados. XMLSignature xmlSig = XmlSignUtil.getInstance().getXMLSignatureFormDocument(xmlDocument).get(0); // Recuperamos el documento Documento documento = XmlSignUtil.getInstance().getDocument(xmlDocument, codFirma); // Recuperamos el mensaje Digest String sha1 = XmlSignUtil.getInstance().getDigestFormated(xmlSig, codFirma); String url = URL_PUBLIC_VERIFICATION + codFirma; // Verificamos y modificamos si es necesario la URL de custodia url = QRCodeUtil.getInstance().buildFriendlyURLIfNeeded(url); // Recuperamos los datos firmados digitalmente. if (texto == null || textoQR == null) { CertificadoGenerico certificado = CertificadoGenericoFactory.getInstance() .generar(xmlSig.getKeyInfo().getX509Certificate()); String[] etiquetas = QRCodeUtil.getInstance().buildTextoEtiqueta(certificado, codFirma, url, sha1); texto = etiquetas[0]; textoQR = etiquetas[1]; } if (log.isDebugEnabled()) log.debug("Generando justificante de firma para fichero " + documento.getNombre()); if (isPdf) { if (documento.getTipo().equals(TypeFile.PDF)) { // Generamos un pdf con la firma al pie. QRCodeUtil.getInstance().firmarPDF(new ByteArrayInputStream(documento.getDatos()), texto, url, textoQR, codFirma, out); } else if (documento.getTipo().isImagen()) { // Generamos un PDF con la imagen y el pie de firma. QRCodeUtil.getInstance().generarImagenPdf(documento.getDatos(), texto, url, textoQR, codFirma, out); } else { // TODO Para el caso particular de la factuaee, crear un // formato de previsualizacin decente. // Generamos un justificante sin contenido. QRCodeUtil.getInstance().generarPdf(texto, url, textoQR, codFirma, out); } } else { return QRCodeUtil.getInstance().generate(texto, url, textoQR, codFirma); } } catch (ExcepcionErrorInterno e) { throw e; } catch (Exception e) { log.fatal("No se puede adjuntar el Cdigo QR a la firma con cdigo de firma: " + codFirma, e); throw new ExcepcionErrorInterno(CodigoError.ERROR_PDF); } return out.toByteArray(); } // ********************************************** // Oyente de contexto que activa el nucleo cuando // arranca la aplicacion // ********************************************** /** * Muestra un mensaje cuando se apacha el Nucleo. * * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) */ @Override public void contextDestroyed(ServletContextEvent contextEvent) { // apagamos las diferentes caches. cacheCertificados.getCacheManager().removalAll(); CacheManager.getInstance().shutdown(); // Detenemos el registro RMI if (rmiRegistry != null) { try { rmiRegistry.unbind(Constantes.NOMBRE_CONECOR_RMI_PUBLICADO); // Detenemos el registro RMI. UnicastRemoteObject.unexportObject(rmiRegistry, true); rmiRegistry = null; } catch (Exception e) { log.warn("No se puede detener el registro RMI del motor de formularios." + e.getMessage()); } log.info("Desactivando el registro RMI"); } // Desactivamos el manejador de conexiones http MultiThreadedHttpConnectionManager.shutdownAll(); System.out.println("Nucleo Viafirma apagado. " + this); super.contextDestroyed(contextEvent); } /** * Oyente de Contexto que se activa al arrancar la aplicacin. * * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) */ @Override public void contextInitialized(ServletContextEvent event) { System.out.println("*******************************************\n\t\tIniciando Viafirma\n" + this + "\n*******************************************"); init(event.getServletContext()); loadProperties(event.getServletContext()); } // ********************************************* // Mtodos de utilidad // ********************************************* /** * Imprime el Copyright del Ncleo * * @see java.lang.Object#toString() */ @Override public String toString() { return "Plataforma de Autenticacin y Firma Digital Viafirma.\n Copyright 2006-2008 Viavansi (www.viavansi.com)"; } /** * Almacena un certificado en cache a la espera de que este sea procesado en * otro momento. * * @param key * Identificador del certificado * @param certificadoX509 * Certificado almacenado */ public void cachearCertificado(String key, X509Certificate certificadoX509) { cacheCertificados.put(new Element(key, certificadoX509)); } /** * Recupera el certificado cacheado * * @param key * Identificador del certificado */ public X509Certificate getCertificadoCacheado(String key) { Element elemento = cacheCertificados.get(key); if (elemento == null) { return null; } else { // elimino el elemento de la cache ya que ya no nos es necesario cacheCertificados.remove(key); return (X509Certificate) elemento.getValue(); } } /** * Recupera el documento cacheado * * @param key * Identificador del documento */ public Documento getDocumentoCacheado(String key) { Element elemento = cacheDocumentToSign.get(key); return (Documento) elemento.getValue(); } /** * Elimina de la cache el fichero con el identificador indicado. * * @param key */ public void removeDocumentoCacheado(String key) { try { cacheDocumentToSign.remove(key); } catch (Exception e) { log.warn("El fichero " + key + " ya ha sido eliminado."); } } /** * Cachea un xml signature. * * @param key * @param signature */ public void cachearXmlDocument(String key, Document signature) { cacheDocumentToSign.put(new Element(key, signature)); } /** * Recupera de la cache el xml signature * * @param key * @param signature * @return */ public Document getXMLDocument(String key) { Element elemento = cacheDocumentToSign.get(key); return (Document) elemento.getObjectValue(); } /** * @param warning_certificado_no_enviado * @param request * @param response */ public void redireccionarError(CodigoError warning_certificado_no_enviado, HttpServletRequest request, HttpServletResponse response) { // Metemos en request los motivos del error request.setAttribute("codError", warning_certificado_no_enviado); FaceletsUtil.forward(request, response, Constantes.URI_ERROR_AUTENTICACION); } /** * Genera un identificador nico. Temporal. posteriormente Custodia generara * uno definitivo. * * @return */ private String generarIdentificador() { return CadenaUtilities.getCurrentInstance().generarRandomIdentificadorTimeStamp(); } /** * Implementacin del patron Singleton. * Nota: El singleton se configura en el arranque de la aplicacin. */ private static Nucleo singleton; public Nucleo() { super(); } /* * (non-Javadoc) * * @seecom.viavansi.framework.core.servlet.StartupServletContextListener# * getClaseDeConstantes() */ @Override protected Class<?> getClaseDeConstantes() { // No se esta utilizando una clase de constantes Global dela aplicacin. return null; } }