source: murachi/murachi/src/main/java/ve/gob/cenditel/murachi/MurachiRESTWS.java @ 0c30a25

Last change on this file since 0c30a25 was 0c30a25, checked in by antonioaraujob <aaraujo@…>, 9 years ago

Agregada documentación del recurso de estadísticas del servicio.

  • Property mode set to 100644
File size: 223.8 KB
Line 
1package ve.gob.cenditel.murachi;
2
3import static java.util.Arrays.asList;
4
5import java.io.ByteArrayInputStream;
6import java.io.ByteArrayOutputStream;
7import java.io.File;
8import java.io.FileInputStream;
9import java.io.FileOutputStream;
10import java.io.IOException;
11import java.io.InputStream;
12import java.io.ObjectInputStream;
13import java.io.ObjectOutputStream;
14import java.io.OutputStream;
15import java.net.URISyntaxException;
16import java.nio.file.Files;
17import java.nio.file.Paths;
18import java.security.GeneralSecurityException;
19import java.security.InvalidKeyException;
20import java.security.KeyStore;
21import java.security.KeyStoreException;
22import java.security.MessageDigest;
23import java.security.NoSuchAlgorithmException;
24import java.security.NoSuchProviderException;
25import java.security.Security;
26import java.security.cert.Certificate;
27import java.security.cert.CertificateException;
28import java.security.cert.CertificateExpiredException;
29import java.security.cert.CertificateFactory;
30import java.security.cert.CertificateNotYetValidException;
31import java.security.cert.X509Certificate;
32import java.util.ArrayList;
33import java.util.Calendar;
34import java.util.Date;
35import java.util.HashMap;
36import java.util.List;
37import java.util.Map;
38import java.util.Map.Entry;
39import java.util.UUID;
40import java.text.DateFormat;
41import java.text.NumberFormat;
42import java.text.SimpleDateFormat;
43
44import javax.ws.rs.Consumes;
45import javax.ws.rs.FormParam;
46import javax.ws.rs.GET;
47import javax.ws.rs.POST;
48import javax.ws.rs.Path;
49import javax.ws.rs.PathParam;
50import javax.ws.rs.Produces;
51import javax.ws.rs.core.Context;
52import javax.ws.rs.core.HttpHeaders;
53import javax.ws.rs.core.MediaType;
54import javax.ws.rs.core.Response;
55import javax.ws.rs.core.Response.ResponseBuilder;
56
57import org.bouncycastle.jce.provider.BouncyCastleProvider;
58import org.bouncycastle.tsp.TimeStampToken;
59import org.glassfish.jersey.media.multipart.FormDataBodyPart;
60import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
61import org.glassfish.jersey.media.multipart.FormDataMultiPart;
62import org.glassfish.jersey.media.multipart.FormDataParam;
63import org.json.JSONArray;
64import org.json.JSONObject;
65
66import com.itextpdf.text.DocumentException;
67import com.itextpdf.text.Rectangle;
68import com.itextpdf.text.exceptions.InvalidPdfException;
69import com.itextpdf.text.pdf.AcroFields;
70import com.itextpdf.text.pdf.PdfDate;
71import com.itextpdf.text.pdf.PdfDictionary;
72import com.itextpdf.text.pdf.PdfName;
73import com.itextpdf.text.pdf.PdfReader;
74import com.itextpdf.text.pdf.PdfSignature;
75import com.itextpdf.text.pdf.PdfSignatureAppearance;
76import com.itextpdf.text.pdf.PdfStamper;
77import com.itextpdf.text.pdf.PdfString;
78import com.itextpdf.text.pdf.security.CertificateInfo;
79import com.itextpdf.text.pdf.security.CertificateVerification;
80import com.itextpdf.text.pdf.security.DigestAlgorithms;
81import com.itextpdf.text.pdf.security.ExternalDigest;
82import com.itextpdf.text.pdf.security.PdfPKCS7;
83import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
84import com.itextpdf.text.pdf.security.SignaturePermissions;
85import com.itextpdf.text.pdf.security.VerificationException;
86
87import ee.sk.digidoc.CertValue;
88import ee.sk.digidoc.DigiDocException;
89import ee.sk.digidoc.SignedDoc;
90import ee.sk.digidoc.factory.DigiDocGenFactory;
91import eu.europa.ec.markt.dss.exception.DSSException;
92
93import javax.servlet.http.HttpServletRequest;
94import javax.servlet.http.HttpServletResponse;
95import javax.servlet.http.HttpSession;
96
97import org.digidoc4j.Configuration;
98import org.digidoc4j.Container;
99import org.digidoc4j.Container.DocumentType;
100import org.digidoc4j.DataFile;
101import org.digidoc4j.Signature;
102import org.digidoc4j.SignatureParameters;
103import org.digidoc4j.SignatureProductionPlace;
104import org.digidoc4j.SignedInfo;
105import org.digidoc4j.ValidationResult;
106import org.digidoc4j.Container.SignatureProfile;
107import org.digidoc4j.X509Cert;
108import org.digidoc4j.exceptions.DigiDoc4JException;
109import org.digidoc4j.exceptions.SignatureNotFoundException;
110import org.digidoc4j.impl.DDocContainer;
111import org.digidoc4j.impl.DDocSignature;
112import org.digidoc4j.impl.ValidationResultForDDoc;
113import org.digidoc4j.signers.PKCS12Signer;
114
115import ve.gob.cenditel.murachi.MurachiException;
116
117import org.apache.log4j.Logger;
118import org.apache.tika.Tika;
119
120
121@Path("/archivos")
122public class MurachiRESTWS {
123       
124        final static Logger logger = Logger.getLogger(MurachiRESTWS.class);
125       
126        private static final String API_VERSION = "0.1.0";
127       
128        // debe colocarse la barra al final de la ruta
129        //private static final String SERVER_UPLOAD_LOCATION_FOLDER = "/tmp/murachi/";
130        private static final String SERVER_UPLOAD_LOCATION_FOLDER = "/var/lib/tomcat7/murachiWorkingDirectory/";
131               
132        private static final String SHA256_MESSAGE_DIGEST = "SHA256";
133       
134        private static final String RSA_DIGEST_ENCRYPTION_ALGORITHM = "RSA";
135       
136        private final String DIGIDOC4J_CONFIGURATION = getAbsolutePathOfResource("digidoc4j.yaml");
137       
138        private final String DIGIDOC4J_TSL_LOCATION = "file://" + getAbsolutePathOfResource("venezuela-tsl.xml");
139       
140        private final String databaseHost = "localhost";
141       
142        private final String databasePort = "5432";
143       
144        private final String databaseName = "databasemurachi";
145       
146        private final String databaseLogin = "aaraujo";
147       
148        private final String databasePassword = "aaraujo";
149       
150
151        // para reportes de advertencias de BDOC
152        private static boolean bdocWarnings = true;
153       
154        // para reportes en modo verbose de BDOC
155        private static boolean bdocVerboseMode = true;
156
157        /**
158         * Retorna la ruta absoluta de un archivo recurso
159         * @param resource cadena con el nombre del archivo
160         * @return ruta absoluta de un archivo recurso
161         */
162        String getAbsolutePathOfResource(String resource) {
163                ClassLoader classLoader = getClass().getClassLoader();
164                File file = new File(classLoader.getResource(resource).getFile());
165                logger.debug("archivo recurso solicitado: "+ resource +" path abosulto: " + file.getAbsolutePath());
166                return file.getAbsolutePath();         
167        }
168       
169        /**
170         * Función para verificar si un archivo existe en el sistema de archivos
171         * @param path ruta absoluta al archivo
172         * @return si el archivo existe en el sistema de archivos
173         */
174        public static boolean checkFileExists(String path)
175        {
176            return new File(path).exists();
177        }
178       
179       
180        /**
181         * Retorna la version del api del servicio
182         * @return version del api del servicio
183         * @throws URISyntaxException
184         *
185         * @api {get} /Murachi/0.1/archivos/version Retorna la versión del API
186         * @apiName GetVersion
187         * @apiGroup General
188         * @apiVersion 0.1.0
189         *
190         * @apiExample Example usage:
191     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/version -H "Authorization: Basic YWRtaW46YWRtaW4="
192         *
193         * @apiSuccess {String} murachiVersion Versión del API
194         */
195        @Path("/version")
196        @GET
197        @Produces(MediaType.APPLICATION_JSON)
198        @Authenticator
199        public Response returnVersion() {
200                logger.info("/version: Murachi Version: " + API_VERSION);       
201                JSONObject jsonObject = new JSONObject();
202                jsonObject.put("murachiVersion", API_VERSION);
203                String result = jsonObject.toString();
204                return Response.status(200).entity(result).build();
205        }
206               
207        /**
208         * Carga un archivo pasado a través de un formulario y retorna
209         * un json con el id del archivo en el servidor para futuras consultas
210         * de estado de firmas
211         *
212         * @param uploadedInputStream stream para obtener el archivo
213         * @param fileDetails datos del archivo
214         * @return
215         * @throws MurachiException
216         *
217         * @api {post} /Murachi/0.1/archivos/ Carga un archivo
218         * @apiName Archivos
219         * @apiGroup Archivos
220         * @apiVersion 0.1.0
221         * @apiDescription Carga un archivo a través de un formulario y retorna un json con el id del archivo en el servidor
222         *
223         *
224         * @apiExample Example usage:
225     * 
226     *  var formData = new FormData();
227     *  formData.append("upload", $("#file-sign")[0].files[0]);           
228     *  $.ajax({
229     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos",
230     *           type: "post",
231     *           dataType: "json",
232     *           data: formData,
233     *           cache: false,
234     *           contentType: false,
235         *           processData: false,
236         *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
237     *           success: function(response) {
238     *                  //identificador del archivo en el servidor
239         *                  var fileId = response.fileId.toString();
240         *                  alert("fileId: "+ fileId);
241         *           },
242         *           error: function(response){
243         *                  alert("error: " + response.error.toString());
244         *           }
245     *  });
246         *
247         * @apiErrorExample {json} Error-Response:
248         *     HTTP/1.1 400 Bad Request
249         *     {
250         *       "error": "datos recibidos del formulario son nulos"
251         *     }
252         *     HTTP/1.1 401 Unauthorized
253         *     {
254         *       "error": "acceso no autorizado"
255         *     }
256         *     
257         *     HTTP/1.1 500
258         *     {
259         *       "error": "IOException"
260         *     }
261         *
262         * @apiSuccess {String} fileId Identificador único del archivo cargado en el servidor.
263         *
264         */     
265        @POST
266        @Path("/")
267        @Consumes(MediaType.MULTIPART_FORM_DATA)
268        @Produces(MediaType.APPLICATION_JSON)
269        @Authenticator
270        public Response uploadFile(
271                        @FormDataParam("upload") InputStream uploadedInputStream,
272                        @FormDataParam("upload") FormDataContentDisposition fileDetails) throws MurachiException {
273               
274                logger.info("/: uploadFile");
275               
276                if (uploadedInputStream == null) {
277                        System.out.println("uploadedInputStream == null");
278                        logger.error("uploadedInputStream != null. datos recibidos del formulario son nulos.");
279                        //throw new MurachiException("uploadedInputStream != null. datos recibidos del formulario son nulos.");
280                       
281                        return Response.status(400).entity("{\"error\": \"datos recibidos del formulario son nulos\"}").type(MediaType.APPLICATION_JSON).build();
282                }
283               
284                if (fileDetails == null) {
285                        System.out.println("fileDetails == null");
286                        logger.error("fileDetails == null. datos recibidos del formulario son nulos.");
287                        //throw new MurachiException("fileDetails == null. datos recibidos del formulario son nulos.");
288                        return Response.status(400).entity("{\"error\": \"datos recibidos del formulario son nulos\"}").type(MediaType.APPLICATION_JSON).build();
289                }
290                               
291                String fileId = UUID.randomUUID().toString();
292                System.out.println(fileId);
293               
294                saveToDisk(uploadedInputStream, fileDetails, fileId);
295               
296                try {
297                        uploadedInputStream.close();
298                } catch (IOException e) {
299                        logger.error("Ocurrio una excepcion: ", e);
300                        e.printStackTrace();
301                        //throw new MurachiException(e.getMessage());
302                        return Response.status(500).entity("{\"error\":" + e.getMessage()).build();
303                       
304                }
305               
306                JSONObject jsonObject = new JSONObject();
307                jsonObject.put("fileId", fileId);
308               
309                System.out.println("File saved to server location : " + SERVER_UPLOAD_LOCATION_FOLDER + fileId);
310                String result = jsonObject.toString();
311                logger.info("/: " + result);
312               
313                return Response.status(200).entity(result).build();
314        }
315
316        /**
317         * Descarga un archivo existente en el servidor
318         * @param fileName nombre (identificador) del archivo que se desea descargar
319         * @return archivo existente en el servidor y pasado como argumento
320         *
321         * @api {get} /Murachi/0.1/archivos/descargas/{id} Descarga un archivo
322         * @apiDescription Descarga un archivo existente en el servidor
323         * @apiName Descargas
324         * @apiGroup Archivos
325         * @apiVersion 0.1.0
326         *
327         * @apiParam {String} id Identificador del archivo que se desea descargar.
328         *
329         * @apiExample Example usage:
330     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/descargas/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee
331         *       
332         *
333         * @apiErrorExample {json} Error-Response:
334         *     HTTP/1.1 404 Not Found
335         *     {
336         *       "fileExist": false
337         *     }
338         */
339        @GET
340        @Path("/descargas/{filename}")
341        @Produces(MediaType.APPLICATION_OCTET_STREAM)
342        public Response downloadFilebyPath(@PathParam("filename")  String fileName) {
343                logger.info("/descargas/{"+fileName+"}");
344                return downloadFileFromServer(fileName);
345        }
346       
347        /**
348         * Descarga un archivo pasado como argumento del servidor
349         * @param fileName nombre o identificador del archivo que se desea descargar
350         * @return archivo pasado como argumento del servidor
351         */
352        /*
353        private Response downloadFileFromServer(String fileName) {   
354            String fileLocation = SERVER_UPLOAD_LOCATION_FOLDER + fileName;
355            Response response = null;
356            NumberFormat myFormat = NumberFormat.getInstance();
357            myFormat.setGroupingUsed(true);
358                     
359            // Retrieve the file
360            File file = new File(SERVER_UPLOAD_LOCATION_FOLDER + fileName);
361            if (file.exists()) {
362                ResponseBuilder builder = Response.ok(file);
363                builder.header("Content-Disposition", "attachment; filename=" + file.getName());
364                response = builder.build();
365               
366                long file_size = file.length();
367                logger.info(String.format("Inside downloadFile==> fileName: %s, fileSize: %s bytes",
368                                fileName, myFormat.format(file_size)));
369            } else {
370                logger.error(String.format("Inside downloadFile==> FILE NOT FOUND: fileName: %s",
371                                fileName));
372                       
373                response = Response.status(404).entity("{\"fileExist\": false}").type("text/plain").build();
374            }
375             
376            return response;
377          }
378        */
379       
380        /**
381         * Descarga un archivo pasado como argumento del servidor
382         * @param fileName nombre o identificador del archivo que se desea descargar
383         * @return archivo pasado como argumento del servidor
384         */
385        private Response downloadFileFromServer(String fileName) {   
386                logger.info("downloadFileFromServer{"+fileName+"}");
387           
388            File file = null;
389           
390            Response response = null;
391           
392           
393            ResponseBuilder builder = null;
394           
395            NumberFormat myFormat = NumberFormat.getInstance();
396            myFormat.setGroupingUsed(true);
397                     
398            // Retrieve the file
399           
400            if (checkFileExists(SERVER_UPLOAD_LOCATION_FOLDER + fileName + "-serialized.bin")) {
401               
402                logger.debug("  descarga de contenedor BDOC: " + SERVER_UPLOAD_LOCATION_FOLDER + fileName + "-serialized.bin");
403               
404                try {                           
405                                Security.addProvider(new BouncyCastleProvider());                                               
406                                Container c;
407                       
408                                // deserializar el contenedor
409                                c = deserialize(SERVER_UPLOAD_LOCATION_FOLDER + fileName + "-serialized.bin");
410                               
411                                logger.debug("  deserializado contenedor: " + SERVER_UPLOAD_LOCATION_FOLDER + fileName + "-serialized.bin");
412                               
413                                logger.debug("numero de dataFile: "+ Integer.toString(c.getDataFiles().size()));
414                                logger.debug("numero de firmas: "+ Integer.toString(c.getSignatures().size()));
415                               
416                                if (c.getSignatures().size() > 0) {
417                                        // guardar el contenedor .bdoc
418                                        c.save(SERVER_UPLOAD_LOCATION_FOLDER + fileName + ".bdoc");
419                                        logger.debug("  contenedor " + SERVER_UPLOAD_LOCATION_FOLDER + fileName + ".bdoc escrito en sistema de archivos");
420                                       
421                                        file = new File(SERVER_UPLOAD_LOCATION_FOLDER + fileName + ".bdoc");
422                                }
423                                else 
424                                {
425                                        // el contenedor no esta firmado por lo tanto no se puede descargar
426                                        logger.error(" error el contenedor no está firmado y no se puede descargar");
427                                       
428                                        //return Response.status(500).entity("{\"error\": \"el contenedor no esta firmado y no se puede descargar.\"}").build();
429                                        return response = Response.status(500).entity("{\"error\": \"el contenedor no esta firmado y no se puede descargar.\"}").type("text/plain").build();
430                                }
431                        } catch (ClassNotFoundException e) {
432                                logger.error(" error ClassNotFoundException");
433                                                       
434                                return Response.status(500).entity("{\"error\": \"error al deserializar contenedor\"}").build();
435                               
436                        } catch (IOException e) {
437                                logger.error("error en la serializacion del contenedor");
438                               
439                                return Response.status(500).entity("{\"error\": \"error al deserializar contenedor\"}").build();
440                        }
441            } 
442            else if (checkFileExists(SERVER_UPLOAD_LOCATION_FOLDER + fileName)) 
443            {
444                file = new File(SERVER_UPLOAD_LOCATION_FOLDER + fileName);
445                logger.debug("  descarga de archivo PDF");
446            }
447            else
448            {
449                logger.error(String.format("Inside downloadFile==> FILE NOT FOUND: fileName: %s",
450                                fileName));
451                       
452                 return response = Response.status(404).entity("{\"fileExist\": false}").
453                                type("text/plain").build();
454            }
455           
456            builder = Response.ok(file);
457        builder.header("Content-Disposition", "attachment; filename=" + file.getName());
458        response = builder.build();
459       
460        long file_size = file.length();
461        logger.info(String.format("Inside downloadFile==> fileName: %s, fileSize: %s bytes",
462                        fileName, myFormat.format(file_size)));
463           
464             
465            return response;
466          }
467       
468       
469       
470        /**
471         * Carga un archivo pasado a través de un formulario y retorna
472         * un json con la informacion de la(s) firma(s) del archivo
473         * en caso de que este firmado
474         *
475         * @param uploadedInputStream stream para obtener el archivo
476         * @param fileDetails datos del archivo
477         * @return
478         * @throws MurachiException
479         *
480         * @api {post} /Murachi/0.1/archivos/firmados Carga un archivo y verifica
481         * @apiName Firmados
482         * @apiGroup Archivos
483         * @apiVersion 0.1.0
484         * @apiDescription Carga un archivo a través de un formulario y retorna un json con la información de la firma.
485         *
486         * @apiSuccess {String} fileId Identificador único del archivo en el servidor
487         * @apiSuccess {Boolean} fileExist El archivo se cargó exitosamente en el servidor.
488         * @apiSuccess {String} mimeType Tipo MIME del archivo verificado.
489         * @apiSuccess {String} error Extension not supported. En caso de que el archivo sea diferente de PDF y BDOC.
490         *
491         * @apiSuccess {Number} numberOfSignatures Número de firmas existentes en el archivo.
492         * @apiSuccess {Object[]} signatures Lista de firmas.
493         * @apiSuccess {String}   signatures.signatureType Tipo de firma de archivo PDF: approval
494         * @apiSuccess {String}   signatures.signedOn Fecha en que se realiza la firma.
495         * @apiSuccess {Boolean}   signatures.integrityCheck Chequea la integridad de la firma.
496         * @apiSuccess {String}   signatures.timeStamp Estampilla de tiempo
497         * @apiSuccess {String}   signatures.reason Razón de la firma.
498         * @apiSuccess {String}   signatures.location Ubicación donde se realiza la firma.
499         * @apiSuccess {String}   signatures.alternativeNameOfTheSigner Nombre alternativo del firmante.
500         * @apiSuccess {String}   signatures.signerCertificateValidFrom Fecha de inicio de validez del certificado.
501         * @apiSuccess {Boolean}   signatures.signerCertificateStillValid El certificado todavía está válido.
502         * @apiSuccess {Boolean}   signatures.signerCertificateHasExpired El certificado expiró.
503         * @apiSuccess {Boolean}   signatures.signatureCoversWholeDocument La firma abarca todo el documento PDF.
504         * @apiSuccess {String}   signatures.filterSubtype Tipo de subfiltro: /adbe.pkcs7.sha1, /adbe.pkcs7.detached.
505         * @apiSuccess {String}   signatures.signerCertificateSubject Sujeto firmante.
506         * @apiSuccess {Boolean}   signatures.signerCertificateValidAtTimeOfSigning El certificado es válido en el momento de la firma.
507         * @apiSuccess {String}   signatures.encryptionAlgorithm Algoritmo de cifrado.
508         * @apiSuccess {String}   signatures.timeStampService Servicio de estampillado de tiempo.
509         * @apiSuccess {String}   signatures.digestAlgorithm Algoritmo hash (reseña).
510         * @apiSuccess {Boolean}   signatures.certificatesVerifiedAgainstTheKeyStore Certificado verificado contra el repositorio de certificados confiables.
511         * @apiSuccess {Number}   signatures.documentRevision Número de revisión del documento PDF.
512         * @apiSuccess {String}   signatures.nameOfTheSigner Nombre del firmante.
513         * @apiSuccess {Number}   signatures.totalDocumentRevisions Número total de revisiones del documento PDF.
514         * @apiSuccess {String}   signatures.contactInfo Información de contacto del firmante.
515         * @apiSuccess {Boolean}   signatures.timeStampVerified Estampilla de tiempo verificada.
516         * @apiSuccess {String}   signatures.signerCertificateIssuer Emisor del certificado firmante.
517         * @apiSuccess {String}   signatures.signerCertificateValidTo Fecha de fin de validez del certificado.
518         * @apiSuccess {String} signatures.signerCertificateSerial BDOC: Serial del certificado del firmante.
519         * @apiSuccess {String} signatures.signatureProfile BDOC: Perfil de la firma.
520         * @apiSuccess {String} signatures.signatureMethod BDOC: Algoritmo de firma utilizado.
521         * @apiSuccess {String} signatures.signatureId BDOC: identificador de la firma.
522         * @apiSuccess {String} signatures.signatureSigningTime BDOC: Hora y fecha en que se realiza la firma.
523         * @apiSuccess {Boolean} signatures.signerCertificateIsValid BDOC: El certificado firmante es válido.
524         * @apiSuccess {String} signatures.signerCertificateIssuer BDOC: Emisor del certificado firmante.
525         * @apiSuccess {String} signatures.signatureValidationException BDOC: Exepciones de la validación de la firma.
526         * @apiSuccess {String} signatures.isValid BDOC: Firma electrónica válida.
527         * @apiSuccess {String} signatures.signerCertificateSubjectName BDOC: Nombre del sujeto firmante.
528         *
529         * @apiSuccess {Boolean}   containerValidation BDOC: Especifica si el contenedor posee una estructura válida. 
530         * @apiSuccess {Number}   numberOfDataFiles BDOC: Cantidad de archivos incluidos en el contenedor BDOC.
531         * @apiSuccess {Object[]} dataFiles BDOC: Lista de archivos incluidos en el contenedor.
532         * @apiSuccess {String} dataFiles.name BDOC: Nombre del archivo incluido en el contenedor.
533         * @apiSuccess {String} dataFiles.dataFileSize BDOC: Tamaño del archivo incluido en el contenedor.
534         * @apiSuccess {String} dataFiles.filename BDOC: Nombre del archivo incluido en el contenedor.
535         * @apiSuccess {String} dataFiles.mediaType BDOC: Tipo MIME del archivo incluido en el contenedor.
536         * @apiSuccess {Object[]} signatures BDOC: Lista de firmas del contenedor BDOC
537         *
538         *
539         *
540         * @apiExample Example usage:
541         *
542         *  var formData = new FormData();
543     *  formData.append("upload", $("#file-sign")[0].files[0]);           
544     *  $.ajax({
545     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/firmados",
546     *           type: "post",
547     *           dataType: "json",
548     *           data: formData,
549     *           cache: false,
550     *           contentType: false,
551         *           processData: false,
552         *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
553     *           success: function(response) {
554         *                  var json = JSON.stringify(response);
555         *                  alert(json);
556         *           },
557         *           error: function(response){
558         *                  alert("error: " + response.error.toString());
559         *           }
560     *  });
561         *
562         *
563         *
564         * @apiErrorExample {json} Error-Response:
565         *     HTTP/1.1 400 Bad Request
566         *     {
567         *       "error": "datos recibidos del formulario son nulos"
568         *     }
569         *     
570         *     HTTP/1.1 401 Unauthorized
571         *     {
572         *       "error": "acceso no autorizado"
573         *     }     
574         *     
575         *     HTTP/1.1 500
576         *     {
577         *       "error": "IOException"
578         *     }
579         *     
580         */
581        @POST
582        @Path("/firmados")
583        @Consumes(MediaType.MULTIPART_FORM_DATA)
584        @Produces(MediaType.APPLICATION_JSON)
585        @Authenticator
586        public Response uploadFileAndVerify(
587                        @FormDataParam("upload") InputStream uploadedInputStream,
588                        @FormDataParam("upload") FormDataContentDisposition fileDetails) throws MurachiException {
589               
590                logger.info("/firmados: uploadFileAndVerify");
591               
592                if (uploadedInputStream == null) {
593                        System.out.println("uploadedInputStream == null");
594                        logger.error("uploadedInputStream != null. datos recibidos del formulario son nulos.");
595                        //throw new MurachiException("uploadedInputStream != null. datos recibidos del formulario son nulos.");
596                        return Response.status(400).entity("{\"error\": \"datos recibidos del formulario son nulos\"}").type(MediaType.APPLICATION_JSON).build();
597                }
598               
599                if (fileDetails == null) {
600                        System.out.println("fileDetails == null");
601                        logger.error("fileDetails == null. datos recibidos del formulario son nulos.");
602                        //throw new MurachiException("fileDetails == null. datos recibidos del formulario son nulos.");
603                        return Response.status(400).entity("{\"error\": \"datos recibidos del formulario son nulos\"}").type(MediaType.APPLICATION_JSON).build();
604                       
605                }
606                               
607                String fileId = UUID.randomUUID().toString();
608                System.out.println(fileId);
609               
610                try 
611                {
612                        saveToDisk(uploadedInputStream, fileDetails, fileId);           
613                        uploadedInputStream.close();
614                } catch (IOException e) {
615                        logger.error("Ocurrio una excepcion: ", e);
616                        e.printStackTrace();
617                        //throw new MurachiException(e.getMessage());
618                        return Response.status(500).entity("{\"error\":" + e.getMessage()).build();
619                }
620               
621                System.out.println("File saved to server location : " + SERVER_UPLOAD_LOCATION_FOLDER + fileId);
622               
623                JSONObject jsonObject = new JSONObject();
624                                       
625                jsonObject = verifyALocalFile(fileId);
626                logger.info("/firmados: " + jsonObject.toString());
627                               
628                return Response.status(200).entity(jsonObject.toString()).build();
629        }
630       
631        /**
632         * Escribe un archivo en el sistema de archivos
633         * @param uploadedInputStream
634         * @param fileDetails
635         * @param fileId identificador unico del archivo de acuerdo a UUIDs
636         * @throws MurachiException
637         */
638        private void saveToDisk(InputStream uploadedInputStream, FormDataContentDisposition fileDetails, String fileId) throws MurachiException {
639               
640                String uploadedFileLocation = SERVER_UPLOAD_LOCATION_FOLDER + /*fileDetails.getFileName()*/ fileId;
641               
642                System.out.println("uploadedFileLocation: " + uploadedFileLocation);
643                logger.debug("saveToDisk: uploadedFileLocation: " + uploadedFileLocation);
644               
645                try {
646                        OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
647                        int read = 0;
648                        byte[] bytes = new byte[1024];
649                       
650                        out = new FileOutputStream(new File(uploadedFileLocation));
651                        while ((read = uploadedInputStream.read(bytes)) != -1) {
652                                out.write(bytes, 0, read);
653                               
654                        }
655                        out.flush();
656                        out.close();
657                }
658                catch(IOException e) {
659                        logger.error("saveToDisk: ocurrio una excepcion" + e.getMessage());
660                       
661                        e.printStackTrace();
662                        throw new MurachiException(e.getMessage());
663                }
664        }
665       
666       
667        /**
668         * Verifica si un archivo posee firmas electronicas y retorna informacion
669         * de las mismas en un json.
670         *
671         * @param idFile identificador del archivo a verificar
672         * @return JSON con informacion de las firmas
673         * @throws MurachiException
674         *
675         * @api {get} /Murachi/0.1/archivos/{idFile} Verifica un archivo
676         * @apiName Verifica
677         * @apiGroup Archivos
678         * @apiVersion 0.1.0
679         * @apiDescription Verificar el archivo y retorna un json con la información de las firma(s) electrónica(s)
680         * en caso de estar firmado.
681         *
682         * @apiParam {String} idFile identificador del archivo que se encuentra en el servidor y se desea verificar.
683         *
684         * @apiSuccess {String} fileId Identificador único del archivo en el servidor
685         * @apiSuccess {Boolean} fileExist El archivo se cargó exitosamente en el servidor.
686         * @apiSuccess {String} mimeType Tipo MIME del archivo verificado.
687         * @apiSuccess {String} error Extension not supported. En caso de que el archivo sea diferente de PDF y BDOC.
688         *
689         * @apiSuccess {Number} numberOfSignatures Número de firmas existentes en el archivo.
690         * @apiSuccess {Object[]} signatures Lista de firmas.
691         * @apiSuccess {String}   signatures.signatureType Tipo de firma de archivo PDF: approval
692         * @apiSuccess {String}   signatures.signedOn Fecha en que se realiza la firma.
693         * @apiSuccess {Boolean}   signatures.integrityCheck Chequea la integridad de la firma.
694         * @apiSuccess {String}   signatures.timeStamp Estampilla de tiempo
695         * @apiSuccess {String}   signatures.reason Razón de la firma.
696         * @apiSuccess {String}   signatures.location Ubicación donde se realiza la firma.
697         * @apiSuccess {String}   signatures.alternativeNameOfTheSigner Nombre alternativo del firmante.
698         * @apiSuccess {String}   signatures.signerCertificateValidFrom Fecha de inicio de validez del certificado.
699         * @apiSuccess {Boolean}   signatures.signerCertificateStillValid El certificado todavía está válido.
700         * @apiSuccess {Boolean}   signatures.signerCertificateHasExpired El certificado expiró.
701         * @apiSuccess {Boolean}   signatures.signatureCoversWholeDocument La firma abarca todo el documento PDF.
702         * @apiSuccess {String}   signatures.filterSubtype Tipo de subfiltro: /adbe.pkcs7.sha1, /adbe.pkcs7.detached.
703         * @apiSuccess {String}   signatures.signerCertificateSubject Sujeto firmante.
704         * @apiSuccess {Boolean}   signatures.signerCertificateValidAtTimeOfSigning El certificado es válido en el momento de la firma.
705         * @apiSuccess {String}   signatures.encryptionAlgorithm Algoritmo de cifrado.
706         * @apiSuccess {String}   signatures.timeStampService Servicio de estampillado de tiempo.
707         * @apiSuccess {String}   signatures.digestAlgorithm Algoritmo hash (reseña).
708         * @apiSuccess {Boolean}   signatures.certificatesVerifiedAgainstTheKeyStore Certificado verificado contra el repositorio de certificados confiables.
709         * @apiSuccess {Number}   signatures.documentRevision Número de revisión del documento PDF.
710         * @apiSuccess {String}   signatures.nameOfTheSigner Nombre del firmante.
711         * @apiSuccess {Number}   signatures.totalDocumentRevisions Número total de revisiones del documento PDF.
712         * @apiSuccess {String}   signatures.contactInfo Información de contacto del firmante.
713         * @apiSuccess {Boolean}   signatures.timeStampVerified Estampilla de tiempo verificada.
714         * @apiSuccess {String}   signatures.signerCertificateIssuer Emisor del certificado firmante.
715         * @apiSuccess {String}   signatures.signerCertificateValidTo Fecha de fin de validez del certificado.
716         * @apiSuccess {String} signatures.signerCertificateSerial BDOC: Serial del certificado del firmante.
717         * @apiSuccess {String} signatures.signatureProfile BDOC: Perfil de la firma.
718         * @apiSuccess {String} signatures.signatureMethod BDOC: Algoritmo de firma utilizado.
719         * @apiSuccess {String} signatures.signatureId BDOC: identificador de la firma.
720         * @apiSuccess {String} signatures.signatureSigningTime BDOC: Hora y fecha en que se realiza la firma.
721         * @apiSuccess {Boolean} signatures.signerCertificateIsValid BDOC: El certificado firmante es válido.
722         * @apiSuccess {String} signatures.signerCertificateIssuer BDOC: Emisor del certificado firmante.
723         * @apiSuccess {String} signatures.signatureValidationException BDOC: Exepciones de la validación de la firma.
724         * @apiSuccess {String} signatures.isValid BDOC: Firma electrónica válida.
725         * @apiSuccess {String} signatures.signerCertificateSubjectName BDOC: Nombre del sujeto firmante.
726         *
727         * @apiSuccess {Boolean}   containerValidation BDOC: Especifica si el contenedor posee una estructura válida. 
728         * @apiSuccess {Number}   numberOfDataFiles BDOC: Cantidad de archivos incluidos en el contenedor BDOC.
729         * @apiSuccess {Object[]} dataFiles BDOC: Lista de archivos incluidos en el contenedor.
730         * @apiSuccess {String} dataFiles.name BDOC: Nombre del archivo incluido en el contenedor.
731         * @apiSuccess {String} dataFiles.dataFileSize BDOC: Tamaño del archivo incluido en el contenedor.
732         * @apiSuccess {String} dataFiles.filename BDOC: Nombre del archivo incluido en el contenedor.
733         * @apiSuccess {String} dataFiles.mediaType BDOC: Tipo MIME del archivo incluido en el contenedor.
734         * @apiSuccess {Object[]} signatures BDOC: Lista de firmas del contenedor BDOC
735         * 
736         *
737         * @apiExample Example usage:
738     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee -H "Authorization: Basic YWRtaW46YWRtaW4="
739         *
740         * @apiErrorExample {json} Error-Response:
741         *     HTTP/1.1 401 Unauthorized
742         *     {
743         *       "error": "acceso no autorizado"
744         *     }
745         *     
746         *     HTTP/1.1 404 Bad Request
747         *     {
748         *       "fileExist": "false"
749         *     }
750         *
751         */
752        /*
753        @GET
754        @Path("/{idFile}")
755        @Produces("application/json")
756        public Response verifyAFile(@PathParam("idFile") String idFile) throws MurachiException {
757
758                System.out.println("/{idFile}");
759                logger.info("/{"+idFile+"}");
760               
761                String file = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
762               
763                File tmpFile = new File(file);
764               
765                JSONObject jsonObject = new JSONObject();
766               
767                if (!tmpFile.exists()) {
768                        System.out.println("File : " + file + " does not exists.");
769                        jsonObject.put("fileExist", "false");
770                        logger.error("fileExist: false");
771                       
772                        return Response.status(404).entity(jsonObject.toString()).build();
773                       
774                }else{
775                        System.out.println("File : " + file + " exists.");
776                        jsonObject.put("fileExist", "true");
777                       
778                        String mime = getMimeType(file);
779                        System.out.println("mimetype : " + mime);
780                       
781                        if (mime.equals("application/pdf")){
782                                System.out.println(" PDF ");
783                               
784                                jsonObject = verifySignaturesInPdf(file);
785                               
786                        //}else if (mime.equals("application/vnd.etsi.asic-e+zip")){
787                        }else if (mime.equals("application/zip") ){
788                                System.out.println("BDOC");                             
789                                //jsonObject.put("formato", "BDOC");
790                                //jsonObject.put("resultado", "NO IMPLEMENTADO");
791                               
792                                jsonObject = verifySignaturesInBdoc(file);
793                        }else{
794                                System.out.println("extension no reconocida");
795                                jsonObject.put("fileExist", "true");
796                                jsonObject.put("error", "extension not supported");
797                                logger.error("error: extension not supported");
798                                //return Response.status(500).entity(jsonObject.toString()).build();
799                        }
800                }
801                String result = jsonObject.toString();
802                logger.info("/{"+idFile+"}: "+ result);
803                return Response.status(200).entity(result).build();     
804        }
805        */     
806        @GET
807        @Path("/{idFile}")
808        @Produces("application/json")
809        @Authenticator
810        public Response verifyAFile(@PathParam("idFile") String idFile) throws MurachiException {
811               
812                JSONObject jsonObject = new JSONObject();
813                String result = "";
814                String path = "";
815               
816                // verificar si existe como contenedor BDOC serializado
817                if (checkFileExists(SERVER_UPLOAD_LOCATION_FOLDER + idFile + "-serialized.bin")) {
818                   
819                        path = SERVER_UPLOAD_LOCATION_FOLDER + idFile + "-serialized.bin";
820                       
821                        logger.debug("  verificar contenedor BDOC serializado: " + SERVER_UPLOAD_LOCATION_FOLDER + idFile + "-serialized.bin");
822                    jsonObject = verifySignaturesInBdoc(path, true);
823                        result = jsonObject.toString();
824                        logger.info("/{"+idFile+"}: "+ result);
825                       
826                    return Response.status(200).entity(result).build();
827                } 
828                // verificar si existe el archivo
829                else if (checkFileExists(SERVER_UPLOAD_LOCATION_FOLDER + idFile)) {
830                        // archivo si existe y es BDOC no serializado
831                        path = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
832                                       
833                        String mime = getMimeType(path);
834                        System.out.println("mimetype : " + mime);
835                       
836                       
837                        if (mime.equals("application/zip")) {
838                                jsonObject = verifySignaturesInBdoc(path, false);
839                                result = jsonObject.toString();
840                                logger.info("/{"+idFile+"}: "+ result);
841                               
842                                // registrar la verificacion exitosa en el contador de verificaciones
843                                registerAVerification(1);
844                               
845                                return Response.status(200).entity(result).build();
846                        }
847                        // archivo si existe y es un pdf
848                        else if (mime.equals("application/pdf")) {
849                                path = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
850                               
851                                jsonObject = verifySignaturesInPdf(path);
852                                result = jsonObject.toString();
853                                logger.info("/{"+idFile+"}: "+ result);
854                               
855                                // registrar la verificacion exitosa en el contador de verificaciones
856                                registerAVerification(0);
857                               
858                                return Response.status(200).entity(result).build();                             
859                        }
860                        // el archivo existe pero es una extension no reconocida
861                        else 
862                        {
863                                // registrar la verificacion exitosa en el contador de verificaciones
864                                registerAVerification(2);
865                               
866                                jsonObject.put("fileExist", "true");
867                                jsonObject.put("error", "extension not supported");
868                                return Response.status(200).entity(jsonObject.toString()).build();
869                        }                       
870                }       
871                // definitivamente el archivo no existe en el sistema de archivos
872                else
873                {
874                        jsonObject.put("fileExist", "false");
875                        logger.error("fileExist: false");
876                       
877                        return Response.status(404).entity(jsonObject.toString()).build();
878                         
879                }
880                               
881        }
882       
883       
884        /**
885         * Verifica si un archivo local posee firmas electronicas y retorna informacion
886         * de las mismas en un json.
887         *
888         * @param idFile identificador del archivo a verificar
889         * @return JSONObject con informacion de las firmas
890         * @throws MurachiException
891         */
892        /*
893        public JSONObject verifyALocalFile(String idFile) throws MurachiException {
894               
895                System.out.println("verifyALocalFile: " + idFile);
896                logger.debug("verifyALocalFile: " + idFile);
897               
898                String file = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
899               
900                File tmpFile = new File(file);
901               
902                JSONObject jsonObject = new JSONObject();
903               
904                jsonObject.put("fileId", idFile);
905               
906                if (!tmpFile.exists()) {
907                        System.out.println("File : " + file + " does not exists.");
908                        jsonObject.put("fileExist", "false");
909                        logger.debug("fileExist: false");
910                       
911                }else{
912                        System.out.println("File : " + file + " exists.");
913                        jsonObject.put("fileExist", "true");
914                       
915                        //String mime = getMimeType(file);
916                        String mime = getMimeTypeWithTika(file);
917                                               
918                        System.out.println("mimetype : " + mime);
919                       
920                        if (mime.equals("application/pdf")){
921                                System.out.println(" PDF ");
922                               
923                                jsonObject = verifySignaturesInPdf(file);
924                               
925                        //}else if (mime.equals("application/vnd.etsi.asic-e+zip")){
926                        }else if (mime.equals("application/zip") ){
927                                System.out.println("BDOC");                             
928                                //jsonObject.put("formato", "BDOC");
929                                //jsonObject.put("resultado", "NO IMPLEMENTADO");
930                               
931                                jsonObject = verifySignaturesInBdoc(file, false);
932                        }else{
933                                System.out.println("extension no reconocida");
934                                jsonObject.put("fileExist", "true");
935                                jsonObject.put("error", "extension not supported");     
936                                logger.debug("error: extension not supported");
937                        }
938                }
939                return jsonObject;
940        }
941        */
942        public JSONObject verifyALocalFile(String idFile) throws MurachiException {
943               
944                JSONObject jsonObject = new JSONObject();
945                String result = "";
946                String path = "";
947               
948                // verificar si existe como contenedor BDOC serializado
949                if (checkFileExists(SERVER_UPLOAD_LOCATION_FOLDER + idFile + "-serialized.bin")) {
950                   
951                        path = SERVER_UPLOAD_LOCATION_FOLDER + idFile + "-serialized.bin";
952                       
953                        logger.debug("  verificar contenedor BDOC serializado: " + SERVER_UPLOAD_LOCATION_FOLDER + idFile + "-serialized.bin");
954                    jsonObject = verifySignaturesInBdoc(path, true);
955                        result = jsonObject.toString();
956                        logger.info("/{"+idFile+"}: "+ result);
957                       
958                    return jsonObject;
959                } 
960                // verificar si existe el archivo
961                else if (checkFileExists(SERVER_UPLOAD_LOCATION_FOLDER + idFile)) {
962                        // archivo si existe y es BDOC no serializado
963                        path = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
964                                       
965                        String mime = getMimeType(path);
966                        System.out.println("mimetype : " + mime);
967                                               
968                        if (mime.equals("application/zip")) {
969                                jsonObject = verifySignaturesInBdoc(path, false);
970                                result = jsonObject.toString();
971                                logger.info("/{"+idFile+"}: "+ result);
972                               
973                                // registrar la verificacion exitosa en el contador de verificaciones
974                                registerAVerification(1);
975                               
976                                return jsonObject;
977                        }
978                        // archivo si existe y es un pdf
979                        else if (mime.equals("application/pdf")) {
980                                path = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
981                               
982                                jsonObject = verifySignaturesInPdf(path);
983                                result = jsonObject.toString();
984                                logger.info("/{"+idFile+"}: "+ result);
985                               
986                                // registrar la verificacion exitosa en el contador de verificaciones
987                                registerAVerification(0);
988                               
989                                return jsonObject;                             
990                        }
991                        // el archivo existe pero es una extension no reconocida
992                        else 
993                        {
994                                jsonObject.put("fileExist", "true");
995                                jsonObject.put("error", "extension not supported");
996                               
997                                // registrar la verificacion exitosa en el contador de verificaciones
998                                registerAVerification(2);
999                               
1000                                return jsonObject;
1001                        }                       
1002                }       
1003                // definitivamente el archivo no existe en el sistema de archivos
1004                else
1005                {
1006                        jsonObject.put("fileExist", "false");
1007                        logger.error("fileExist: false");
1008                       
1009                        return jsonObject;
1010                         
1011                }
1012        }
1013       
1014       
1015       
1016       
1017       
1018        /**
1019         * Retorna un JSON con informacion de las firmas del documento PDF
1020         * @param pdfFile archivo pdf a verificar
1021         * @return JSON con informacion de las firmas del documento PDF
1022         * @throws MurachiException
1023         */
1024        private JSONObject verifySignaturesInPdf(String pdfFile) throws MurachiException {
1025               
1026                logger.debug("verifySignaturesInPdf: "+ pdfFile);
1027               
1028                java.nio.file.Path path = Paths.get(pdfFile);
1029                String idFile = path.getFileName().toString();
1030               
1031               
1032                JSONObject jsonSignatures = new JSONObject();
1033                JSONArray jsonArray = new JSONArray();
1034               
1035                try {
1036                       
1037                        Security.addProvider(new BouncyCastleProvider());
1038                       
1039                        PdfReader reader = new PdfReader(pdfFile);
1040                        AcroFields af = reader.getAcroFields();
1041                        ArrayList<String> names = af.getSignatureNames();
1042                        if (names.size() <= 0) {
1043                                jsonSignatures.put("fileExist", "true");
1044                                jsonSignatures.put("fileId", idFile);
1045                                jsonSignatures.put("numberOfSignatures", "0");
1046                                jsonSignatures.put("mimeType", "application/pdf");
1047                        }else{
1048                               
1049                                jsonSignatures.put("fileExist", "true");
1050                                jsonSignatures.put("fileId", idFile);
1051                                jsonSignatures.put("numberOfSignatures", names.size());
1052                                jsonSignatures.put("mimeType", "application/pdf");
1053                                                               
1054                                HashMap<String, String> signatureInformation;
1055                               
1056                                // inicializar el keystore para verificacion
1057                                KeyStore ks = setupKeyStore();
1058                               
1059                                for (String name : names) {
1060                                        System.out.println("===== " + name + " =====");
1061                                        signatureInformation = verifySignature(af, name, ks);
1062                                        System.out.println("signatureInformation.size " + signatureInformation.size());
1063                                       
1064                                        JSONObject jo = getJSONFromASignature(signatureInformation);
1065                                        System.out.println("jo:  " + jo.toString());
1066                                        jsonArray.put(jo);
1067                                }       
1068                                jsonSignatures.put("signatures", jsonArray);
1069                                System.out.println("jsonSignatures :  " + jsonSignatures.toString());
1070                               
1071                        }
1072                       
1073                } catch (IOException e) {
1074                        logger.error("verifySignaturesInPdf ocurrio una excepcion", e);
1075                        e.printStackTrace();
1076                        throw new MurachiException(e.getMessage());
1077                } catch (GeneralSecurityException e) {
1078                        logger.error("verifySignaturesInPdf ocurrio una excepcion", e);
1079                        e.printStackTrace();
1080                        throw new MurachiException(e.getMessage());
1081                }
1082                               
1083                return jsonSignatures;         
1084        }
1085       
1086        /**
1087         * Chequea la integridad de una revision basada en una firma electronica
1088         * @param fields Campos
1089         * @param name nombre de la firma
1090         * @return HashMap con campos de informacion de la firma electronica
1091         * @throws GeneralSecurityException falla en
1092         * @throws IOException cuando ca
1093         * @throws MurachiException
1094         */
1095        public HashMap<String, String> verifySignature(AcroFields fields, String name, KeyStore ks) 
1096                        throws GeneralSecurityException, IOException, MurachiException {
1097                       
1098                logger.debug("verifySignature()");
1099                HashMap<String, String> integrityMap = new HashMap<String, String>();
1100               
1101                System.out.println("Signature covers whole document: " + fields.signatureCoversWholeDocument(name));
1102               
1103                integrityMap.put("signatureCoversWholeDocument", Boolean.toString(fields.signatureCoversWholeDocument(name)));
1104               
1105                int revision = fields.getRevision(name);
1106                System.out.println("Document revision: " + fields.getRevision(name) + " of " + fields.getTotalRevisions());             
1107                integrityMap.put("documentRevision", Integer.toString(fields.getRevision(name)));
1108               
1109                System.out.println("Total Document revisions: " + fields.getTotalRevisions());
1110                integrityMap.put("totalDocumentRevisions",  Integer.toString(fields.getTotalRevisions()));
1111                               
1112                PdfPKCS7 pkcs7 = fields.verifySignature(name);
1113        System.out.println("Integrity check OK? " + pkcs7.verify());
1114        integrityMap.put("integrityCheck", Boolean.toString(pkcs7.verify()));
1115       
1116        System.out.println("Digest Algorithm: " + pkcs7.getHashAlgorithm());
1117        integrityMap.put("digestAlgorithm", pkcs7.getHashAlgorithm());
1118       
1119        System.out.println("Encryption Algorithm: " + pkcs7.getEncryptionAlgorithm());
1120        integrityMap.put("encryptionAlgorithm", pkcs7.getEncryptionAlgorithm());
1121       
1122        System.out.println("Filter subtype: " + pkcs7.getFilterSubtype());
1123        integrityMap.put("filterSubtype", pkcs7.getFilterSubtype().toString());
1124       
1125        X509Certificate cert = (X509Certificate) pkcs7.getSigningCertificate();
1126                System.out.println("Name of the signer: " + CertificateInfo.getSubjectFields(cert).getField("CN"));
1127                integrityMap.put("nameOfTheSigner", CertificateInfo.getSubjectFields(cert).getField("CN"));
1128       
1129                if (pkcs7.getSignName() != null){
1130                        System.out.println("Alternative name of the signer: " + pkcs7.getSignName());
1131                        integrityMap.put("alternativeNameOfTheSigner", pkcs7.getSignName());                   
1132                }else{
1133                        System.out.println("Alternative name of the signer: " + "null");
1134                        integrityMap.put("alternativeNameOfTheSigner", "");
1135                }
1136               
1137                SimpleDateFormat date_format = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SS");
1138                System.out.println("Signed on: " + date_format.format(pkcs7.getSignDate().getTime()));
1139                integrityMap.put("signedOn", date_format.format(pkcs7.getSignDate().getTime()).toString());
1140               
1141                if (pkcs7.getTimeStampDate() != null) {
1142                        System.out.println("TimeStamp: " + date_format.format(pkcs7.getTimeStampDate().getTime()));
1143                        integrityMap.put("timeStamp", date_format.format(pkcs7.getTimeStampDate().getTime()).toString());
1144                        TimeStampToken ts = pkcs7.getTimeStampToken();
1145                        System.out.println("TimeStamp service: " + ts.getTimeStampInfo().getTsa());
1146                        integrityMap.put("timeStampService", ts.getTimeStampInfo().getTsa().toString());
1147                        System.out.println("Timestamp verified? " + pkcs7.verifyTimestampImprint());
1148                        integrityMap.put("timeStampVerified", Boolean.toString(pkcs7.verifyTimestampImprint()));
1149                }else{
1150                        System.out.println("TimeStamp: " + "null");
1151                        integrityMap.put("timeStamp", "null");
1152                       
1153                        System.out.println("TimeStamp service: " + "null");
1154                        integrityMap.put("timeStampService", "null");
1155                       
1156                        System.out.println("Timestamp verified?: " + "null");
1157                        integrityMap.put("timeStampVerified", "null");
1158                }
1159               
1160                System.out.println("Location: " + pkcs7.getLocation());
1161                integrityMap.put("location", pkcs7.getLocation());             
1162               
1163                System.out.println("Reason: " + pkcs7.getReason());
1164                integrityMap.put("reason", pkcs7.getReason());
1165               
1166                PdfDictionary sigDict = fields.getSignatureDictionary(name);
1167                PdfString contact = sigDict.getAsString(PdfName.CONTACTINFO);
1168                if (contact != null){
1169                        System.out.println("Contact info: " + contact);
1170                        integrityMap.put("contactInfo", contact.toString());                   
1171                }else{
1172                        System.out.println("Contact info: " + "null");
1173                        integrityMap.put("contactInfo", "null");
1174                }
1175                       
1176                SignaturePermissions perms = null;
1177                perms = new SignaturePermissions(sigDict, perms);
1178                System.out.println("Signature type: " + (perms.isCertification() ? "certification" : "approval"));
1179                integrityMap.put("signatureType", (perms.isCertification() ? "certification" : "approval"));
1180               
1181               
1182                //KeyStore ks = setupKeyStore();
1183               
1184                Certificate[] certs = pkcs7.getSignCertificateChain();
1185                Calendar cal = pkcs7.getSignDate();
1186                List<VerificationException> errors = CertificateVerification.verifyCertificates(certs, ks, cal);
1187                if (errors.size() == 0){               
1188                        System.out.println("Certificates verified against the KeyStore");
1189                        integrityMap.put("certificatesVerifiedAgainstTheKeyStore", "true");
1190                }
1191                else{
1192                        System.out.println(errors);
1193                        integrityMap.put("certificatesVerifiedAgainstTheKeyStore", "false");
1194                }
1195               
1196               
1197                X509Certificate certificateTmp = (X509Certificate) certs[0];
1198                System.out.println("=== Certificate " + Integer.toString(revision) + " ===");
1199
1200                HashMap<String, String> signerCertificateMap = getSignerCertificateInfo(certificateTmp, cal.getTime());
1201                for (Entry<String, String> entry : signerCertificateMap.entrySet()) {
1202                        integrityMap.put(entry.getKey(), entry.getValue());
1203                }
1204               
1205                return integrityMap;
1206        }
1207       
1208        /**
1209         * Construye un objeto JSON a partir del HashMap pasado como argumento
1210         * @param hashMap HashMap que contiene los elementos para construir el JSON
1211         * @return objeto JSON a partir del HashMap pasado como argumento
1212         */
1213        public JSONObject getJSONFromASignature(HashMap<String, String> hashMap) {
1214               
1215                logger.debug("getJSONFromASignature()");
1216                JSONObject jsonSignature = new JSONObject();
1217               
1218                for (Entry<String, String> entry : hashMap.entrySet()) {
1219                    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
1220                    jsonSignature.put(entry.getKey(), entry.getValue());
1221                }               
1222                return jsonSignature;           
1223        }
1224       
1225        /**
1226         * Carga el KeyStore con certificados confiables para la verificacion de certificados
1227         * de firmas
1228         * @return KeyStore con certificados confiables
1229         * @throws MurachiException
1230         */
1231        private KeyStore setupKeyStore() throws MurachiException {
1232                logger.debug("setupKeyStore()");
1233                KeyStore ks = null;
1234                try {
1235                        ks = KeyStore.getInstance(KeyStore.getDefaultType());
1236                       
1237                        ks.load(null, null);
1238                        CertificateFactory cf = CertificateFactory.getInstance("X.509");
1239                        ks.setCertificateEntry("acraiz",
1240                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("CERTIFICADO-RAIZ-SHA384.crt"))));
1241                        ks.setCertificateEntry("pscfii", 
1242                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("PSCFII-SHA256.crt"))));                   
1243                        ks.setCertificateEntry("procert", 
1244                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("PSC-PROCERT-SHA256.crt"))));                     
1245                        ks.setCertificateEntry("altosfuncionarios", 
1246                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("ACALTOS-FUNCIONARIOS-SHA256.crt"))));                     
1247                        ks.setCertificateEntry("acsubordinadafundayacucho", 
1248                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("ACSUBORDINADA-FUNDAYACUCHO.crt"))));                     
1249                        ks.setCertificateEntry("gidsi", 
1250                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("GIDSI.crt"))));
1251                                               
1252                } catch (KeyStoreException e) { 
1253                        logger.error("setupKeyStore() ocurrio una excepcion", e);
1254                        e.printStackTrace();
1255                        throw new MurachiException(e.getMessage());
1256                } catch (NoSuchAlgorithmException e) {
1257                        logger.error("setupKeyStore() ocurrio una excepcion", e);
1258                        e.printStackTrace();
1259                        throw new MurachiException(e.getMessage());
1260                } catch (CertificateException e) {
1261                        logger.error("setupKeyStore() ocurrio una excepcion", e);
1262                        e.printStackTrace();
1263                        throw new MurachiException(e.getMessage());
1264                } catch (IOException e) {
1265                        logger.error("setupKeyStore() ocurrio una excepcion", e);
1266                        e.printStackTrace();
1267                        throw new MurachiException(e.getMessage());
1268                }               
1269                return ks;
1270        }
1271       
1272        /**
1273         * Obtiene informacion del certificado firmante de una revision
1274         * @param cert certificado firmante
1275         * @param signDate fecha en que se realizo la firma
1276         * @return informacion del certificado firmante de una revision en forma de HashMap
1277         * @throws MurachiException
1278         */
1279        public HashMap<String, String> getSignerCertificateInfo(X509Certificate cert, Date signDate) throws MurachiException {
1280                logger.debug("getSignerCertificateInfo()");
1281                HashMap<String, String> signerCertificateMap = new HashMap<String, String>();
1282               
1283                System.out.println("Issuer: " + cert.getIssuerDN());
1284                signerCertificateMap.put("signerCertificateIssuer", cert.getIssuerDN().toString());
1285               
1286               
1287                System.out.println("Subject: " + cert.getSubjectDN());
1288                signerCertificateMap.put("signerCertificateSubject", cert.getSubjectDN().toString());
1289               
1290                SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS");
1291                System.out.println("Valid from: " + date_format.format(cert.getNotBefore()));
1292                signerCertificateMap.put("signerCertificateValidFrom", date_format.format(cert.getNotBefore()).toString());
1293               
1294                System.out.println("Valid to: " + date_format.format(cert.getNotAfter()));
1295                signerCertificateMap.put("signerCertificateValidTo", date_format.format(cert.getNotAfter()).toString());
1296               
1297                try {
1298                        cert.checkValidity(signDate);
1299                        System.out
1300                                        .println("The certificate was valid at the time of signing.");
1301                        signerCertificateMap.put("signerCertificateValidAtTimeOfSigning", "true");
1302                } catch (CertificateExpiredException e) {
1303                        System.out
1304                                        .println("The certificate was expired at the time of signing.");
1305                       
1306                        signerCertificateMap.put("signerCertificateValidAtTimeOfSigning", "false");
1307                       
1308                        signerCertificateMap.put("signerCertificateExpiredAtTimeOfSigning", "true");
1309                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate was expired at the time of signing");
1310                        //throw new MurachiException(e.getMessage());
1311                } catch (CertificateNotYetValidException e) {
1312                        System.out
1313                                        .println("The certificate wasn't valid yet at the time of signing.");
1314                       
1315                        signerCertificateMap.put("signerCertificateValidAtTimeOfSigning", "false");
1316                       
1317                        signerCertificateMap.put("signerCertificateNotValidYetAtTimeOfSigning", "true");
1318                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate wasn't valid yet at the time of signing");
1319                        //throw new MurachiException(e.getMessage());
1320                }
1321                try {
1322                        cert.checkValidity();
1323                        System.out.println("The certificate is still valid.");
1324                        signerCertificateMap.put("signerCertificateStillValid", "true");
1325                } catch (CertificateExpiredException e) {
1326                        System.out.println("The certificate has expired.");
1327                       
1328                        signerCertificateMap.put("signerCertificateStillValid", "false");
1329                       
1330                        signerCertificateMap.put("signerCertificateHasExpired", "true");
1331                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate has expired");
1332                        //throw new MurachiException(e.getMessage());
1333                } catch (CertificateNotYetValidException e) {
1334                        System.out.println("The certificate isn't valid yet.");
1335                       
1336                        signerCertificateMap.put("signerCertificateStillValid", "false");
1337                       
1338                        signerCertificateMap.put("signerCertificateNotValidYet", "true");
1339                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate isn't valid yet");
1340                        //throw new MurachiException(e.getMessage());
1341                }
1342                return signerCertificateMap;
1343        }
1344       
1345       
1346        /**
1347         * Ejecuta el proceso de presign o preparacion de firma de documento pdf.
1348         *
1349         * Estructura del JSON que recibe la funcion:
1350         *
1351         *      {"fileId":"file_id",                           
1352         *      "certificate":"hex_cert_value",
1353         *  "reason":"reason",
1354         *  "location":"location",
1355         *  "contact":"contact"
1356         *  }
1357         *
1358         *
1359         * @param presignPar JSON con los parametros de preparacion: Id del archivo y certificado
1360         * firmante
1361         * @param req objeto request para crear una sesion y mantener elementos del
1362         * pdf en la misma.
1363         * @throws MurachiException
1364         *
1365         * @api {post} /Murachi/0.1/archivos/firmados/pdfs Prepara la firma del documento PDF.
1366         * @apiName Pdfs
1367         * @apiGroup PDFS
1368         * @apiVersion 0.1.0
1369         * @apiDescription Prepara la firma de un documento PDF. Se debe pasar un JSON con la siguiente estructura:
1370         *  {"fileId":"file_id",                               
1371         *      "certificate":"hex_cert_value",
1372         *  "reason":"reason",
1373         *  "location":"location",
1374         *  "contact":"contact",
1375         *  "signatureVisbile":"true"
1376         *  }
1377         * 
1378         *  fileId: corresponde al identificador del archivo que se encuentra en el servidor y se desea firmar.
1379         * 
1380         *  certificate: corresponde al certificado del firmante en formato hexadecimal.
1381         * 
1382         *  reason: corresponde a la razón de la firma (cadena descriptiva del por qué de la firma).
1383         * 
1384         *  location: corresponde a la ubicación donde se realiza la firma.
1385         * 
1386         *  contact: corresponde a información de contacto del firmante.
1387         * 
1388         *  signatureVisible: true para mostrar un indicador visible de firma en la primera página
1389         *  del documento pdf. false para no mostrar un indicador visible de firma en la primera página
1390         *  del documento pdf.
1391         *
1392         * @apiSuccess {String} hash Reseña o hash del archivo que se debe cifrar con la clave privada protegida por el
1393         * dispositivo criptográfico.
1394         *
1395         * @apiExample Example usage:
1396         *
1397         * var parameters = JSON.stringify({
1398         *                             "fileId":fileId,
1399         *                             "certificate":cert.hex,
1400         *                             "reason":"prueba firma web",
1401         *                             "location":"Oficina",
1402         *                             "contact":"582746574336",
1403         *                             "signatureVisible":"true"
1404         *                             });
1405         *
1406         * $.ajax({
1407     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/pdfs",
1408     *           type: "post",
1409     *           dataType: "json",
1410     *           data: parameters,
1411     *           contentType: "application/json",
1412     *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
1413     *           success: function(data, textStatus, jqXHR){
1414         *                              var json_x = data;
1415     *                              var hash = json_x['hash'];
1416     *                              alert("hash recibido del servidor "+hash);
1417     *           },
1418         *           error: function(jqXHR, textStatus, errorThrown){
1419         *                              //alert('error: ' + textStatus);
1420         *                              //var responseText = jQuery.parseJSON(jqXHR.responseText);
1421         *                              alert('ajax error function: ' + jqXHR.responseText);
1422         *                             
1423         *           }
1424     *  });
1425         *
1426         *
1427         *
1428         * @apiErrorExample {json} Error-Response:
1429         *     HTTP/1.1 400 Bad Request
1430         *     {
1431         *       "hash": "",
1432         *       "error": "El archivo que desea firmar no es un PDF."
1433         *     }
1434         *     
1435         *     HTTP/1.1 401 Unauthorized
1436         *     {
1437         *       "error": "acceso no autorizado"
1438         *     }
1439         *     
1440         *     HTTP/1.1 500 Internal Server Error
1441         *     {
1442         *       "hash": "",
1443         *       "error": "error en carga de certificado de firmante"
1444         *     }
1445         *
1446         *
1447         */
1448        @POST
1449        @Path("/pdfs")
1450        @Consumes(MediaType.APPLICATION_JSON)
1451        @Produces(MediaType.APPLICATION_JSON)
1452        @Authenticator
1453        //public PresignHash presignPdf(PresignParameters presignPar, @Context HttpServletRequest req) {
1454        public Response presignPdf(PresignParameters presignPar, @Context HttpServletRequest req) throws MurachiException {
1455               
1456                logger.info("/pdfs");
1457               
1458                PresignHash presignHash = new PresignHash();
1459
1460                String result = "";
1461                if (presignPar == null) {
1462                        logger.error("solicitud mal formada.");
1463                        result = "\"error\":\"solicitud mal formada\"";
1464                        return Response.status(400).entity(result).build();     
1465                }
1466                               
1467                // obtener el id del archivo
1468                String fileId = presignPar.getFileId();
1469                if (fileId == null) {
1470                        logger.debug("fileId == null");
1471                        logger.error("solicitud mal formada: no esta especificado el identificador del archivo PDF.");
1472                        result = "\"error\":\"solicitud mal formada: : no esta especificado el identificador del archivo PDF\"";
1473                        return Response.status(400).entity(result).build();
1474                }
1475                logger.debug("  fileId: " + fileId);
1476               
1477                // cadena con el certificado
1478                String certHex = presignPar.getCertificate();
1479                if (certHex == null) {
1480                        logger.debug("certHex == null");
1481                        logger.error("solicitud mal formada: no esta especificado el certificado del firmante en hexadecimal.");
1482                        result = "\"error\":\"solicitud mal formada: : no esta especificado el certificado del firmante en hexadecimal.\"";
1483                        return Response.status(400).entity(result).build();
1484                }
1485                logger.debug("  certHex: " + certHex);
1486
1487                // razon de la firma
1488                String reason = presignPar.getReason();
1489                if (reason == null) {
1490                        logger.debug("certHex == null");
1491                        logger.error("solicitud mal formada: no esta especificada la razon de la firma.");
1492                        result = "\"error\":\"solicitud mal formada: : no esta especificada la razon de la firma.\"";
1493                        return Response.status(400).entity(result).build();
1494                }
1495                logger.debug("  reason: " + reason);
1496               
1497                // ubicacion de la firma
1498                String location = presignPar.getLocation();
1499                if (location == null) {
1500                        logger.debug("location == null");
1501                        logger.error("solicitud mal formada: no esta especificada la ubicación donde se realiza la firma.");
1502                        result = "\"error\":\"solicitud mal formada: : no esta especificada la ubicación donde se realiza la firma.\"";
1503                        return Response.status(400).entity(result).build();
1504                }
1505                logger.debug("  location: " + location);
1506               
1507                // contacto del firmante
1508                String contact = presignPar.getContact();
1509                if (contact == null) {
1510                        logger.debug("contact == null");
1511                        logger.error("solicitud mal formada: no esta especificada la informacion de contacto del firmante.");
1512                        result = "\"error\":\"solicitud mal formada: : no esta especificada la informacion de contacto del firmante.\"";
1513                        return Response.status(400).entity(result).build();
1514                }
1515                logger.debug("  location: " + location);
1516               
1517                // firma visible
1518                Boolean signatureVisible = presignPar.getSignatureVisible(); 
1519                if (signatureVisible == null) {
1520                        logger.debug("signatureVisible == null");
1521                        logger.error("solicitud mal formada: no esta especificado si la firma PDF es visible o no.");
1522                        result = "\"error\":\"solicitud mal formada: : no esta especificado si la firma PDF es visible o no.\"";
1523                        return Response.status(400).entity(result).build();
1524                }
1525                logger.debug("  signatureVisible: " + Boolean.toString(signatureVisible));
1526               
1527               
1528                String pdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
1529                System.out.println("archivo a firmar: " + pdf);
1530                logger.debug("archivo a firmar: " + pdf);
1531               
1532                String mime = getMimeType(pdf);
1533               
1534                if (!mime.equals("application/pdf")){
1535                        presignHash.setError("El archivo que desea firmar no es un PDF.");
1536                        presignHash.setHash("");
1537                        //return presignHash;
1538                                                                       
1539                        //result = presignHash.toString();
1540                        logger.info("El archivo que desea firmar no es un PDF.");
1541                        return Response.status(400).entity(presignHash).build();                       
1542                }
1543                                                       
1544                try {
1545                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
1546                        Certificate[] chain = new Certificate[1];
1547                       
1548                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
1549                        chain[0] = factory.generateCertificate(in);
1550                       
1551                        if (chain[0] == null) {
1552                                System.out.println("error chain[0] == null");
1553                                logger.error("presignPdf: error en carga de certificado de firmante");
1554                                //throw new MurachiException("presignPdf: error en carga de certificado de firmante");
1555                               
1556                                presignHash.setError("error en carga de certificado de firmante");
1557                                presignHash.setHash("");
1558                                return Response.status(500).entity(presignHash).build();
1559                                                               
1560                        }else {
1561                               
1562                                System.out.println("se cargo el certificado correctamente");
1563                                System.out.println(chain[0].toString());
1564                                logger.debug("se cargo el certificado correctamente");
1565                                logger.debug(chain[0].toString());
1566                        }                       
1567                       
1568                        PdfReader reader = new PdfReader(pdf);                 
1569                       
1570                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1571                       
1572                        //PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
1573                        PdfStamper stamper = null;
1574                       
1575                       
1576                        if (pdfAlreadySigned(reader)){
1577                                stamper = PdfStamper.createSignature(reader, baos, '\0', null, true);
1578                        }else{
1579                                stamper = PdfStamper.createSignature(reader, baos, '\0');
1580                        }
1581
1582                        // crear la apariencia de la firma
1583                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
1584                               
1585                sap.setReason(reason);
1586                sap.setLocation(location);
1587                sap.setContact(contact);
1588               
1589                //sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
1590               
1591                if (!pdfAlreadySigned(reader) && signatureVisible){
1592                        sap.setVisibleSignature(new Rectangle(36, 748, 144, 780),1, "sig1");
1593                        }else{
1594                                if (signatureVisible)
1595                                {
1596                                        int idSig = numberOfSignatures(reader)+1;
1597                                        //sap.setVisibleSignature(new Rectangle(36, 700, 144, 732),1, "sig"+Integer.toString(idSig));
1598                                        sap.setVisibleSignature(
1599                                                        new Rectangle(36, (748-(numberOfSignatures(reader)*38)), 144, (780-(numberOfSignatures(reader)*38))),
1600                                                                1, "sig"+Integer.toString(idSig));     
1601                                }
1602                               
1603                        }
1604               
1605                sap.setCertificate(chain[0]);
1606               
1607                // crear la estructura de la firma
1608                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
1609               
1610               
1611                dic.setReason(sap.getReason());
1612                dic.setLocation(sap.getLocation());
1613                dic.setContact(sap.getContact());
1614                dic.setDate(new PdfDate(sap.getSignDate()));
1615               
1616                sap.setCryptoDictionary(dic);
1617               
1618                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
1619                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
1620                sap.preClose(exc);
1621               
1622                ExternalDigest externalDigest = new ExternalDigest() {
1623                        public MessageDigest getMessageDigest(String hashAlgorithm)
1624                        throws GeneralSecurityException {
1625                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
1626                        }
1627                };
1628                       
1629                       
1630                PdfPKCS7 sgn = new PdfPKCS7(null, chain, SHA256_MESSAGE_DIGEST, null, externalDigest, false);
1631               
1632                InputStream data = sap.getRangeStream();
1633               
1634                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest(SHA256_MESSAGE_DIGEST));
1635               
1636                Calendar cal = Calendar.getInstance();
1637                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
1638               
1639                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest(SHA256_MESSAGE_DIGEST));
1640               
1641                System.out.println("sh length: "+ sh.length);
1642                logger.debug("sh length: "+ sh.length);
1643                       
1644                String hashToSign = byteArrayToHexString(sh);
1645                logger.debug("hashToSign: "+ hashToSign);
1646                logger.debug("length: " +hashToSign.length());
1647                System.out.println("***************************************************************");
1648                System.out.println("HASH EN HEXADECIMAL:");
1649                System.out.println(hashToSign);
1650                System.out.println("length: " +hashToSign.length());   
1651                System.out.println("***************************************************************");
1652                       
1653                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
1654                        Date date = new Date();
1655                        System.out.println(dateFormat.format(date));
1656                        //String d = dateFormat.format(date);
1657                       
1658                       
1659                        // almacenar los objetos necesarios para realizar el postsign en una sesion
1660                        HttpSession session = req.getSession(true);
1661                        session.setAttribute("hashToSign", hashToSign);
1662                       
1663                        session.setAttribute("stamper", stamper);
1664                        session.setAttribute("sgn", sgn);
1665                        session.setAttribute("hash", hash);
1666                        session.setAttribute("cal", cal);
1667                        session.setAttribute("sap", sap);
1668                        session.setAttribute("baos", baos);
1669                        session.setAttribute("fileId", fileId);
1670                       
1671                        presignHash.setHash(hashToSign);
1672                        presignHash.setError("");
1673                               
1674                       
1675                } catch (CertificateException e1) {
1676                        logger.error("presignPdf ocurrio una excepcion ", e1);
1677                        e1.printStackTrace();
1678                        //throw new MurachiException(e1.getMessage());
1679                        presignHash.setError(e1.getMessage());
1680                        presignHash.setHash("");
1681                        return Response.status(500).entity(presignHash).build();                       
1682                       
1683                } catch (InvalidPdfException e) {
1684                        logger.error("presignPdf ocurrio una excepcion ", e);
1685                        e.printStackTrace();
1686                        //presignHash.setError("No se pudo leer el archivo PDF en el servidor");
1687                        //throw new MurachiException(e.getMessage());
1688                        presignHash.setError("No se pudo leer el archivo PDF en el servidor");
1689                        presignHash.setHash("");
1690                        return Response.status(500).entity(presignHash).build();
1691                       
1692                } catch (IOException e) {
1693                        logger.error("presignPdf ocurrio una excepcion ", e);
1694                        e.printStackTrace();
1695                        //throw new MurachiException(e.getMessage());
1696                       
1697                        presignHash.setError(e.getMessage());
1698                        presignHash.setHash("");
1699                        return Response.status(500).entity(presignHash).build();
1700                       
1701                } catch (DocumentException e) {
1702                        logger.error("presignPdf ocurrio una excepcion ", e);
1703                        e.printStackTrace();
1704                        //throw new MurachiException(e.getMessage());
1705                       
1706                        presignHash.setError(e.getMessage());
1707                        presignHash.setHash("");
1708                        return Response.status(500).entity(presignHash).build();
1709                       
1710                } catch (InvalidKeyException e) {
1711                        logger.error("presignPdf ocurrio una excepcion ", e);
1712                        //e.printStackTrace();
1713                        //throw new MurachiException(e.getMessage());
1714                       
1715                        presignHash.setError(e.getMessage());
1716                        presignHash.setHash("");
1717                        return Response.status(500).entity(presignHash).build();
1718                       
1719                } catch (NoSuchProviderException e) {
1720                        logger.error("presignPdf ocurrio una excepcion ", e);
1721                        //e.printStackTrace();
1722                        //throw new MurachiException(e.getMessage());
1723                       
1724                        presignHash.setError(e.getMessage());
1725                        presignHash.setHash("");
1726                        return Response.status(500).entity(presignHash).build();
1727                       
1728                } catch (NoSuchAlgorithmException e) {
1729                        logger.error("presignPdf ocurrio una excepcion ", e);
1730                        //e.printStackTrace();
1731                        //throw new MurachiException(e.getMessage());
1732                       
1733                        presignHash.setError(e.getMessage());
1734                        presignHash.setHash("");
1735                        return Response.status(500).entity(presignHash).build();
1736                       
1737                } catch (GeneralSecurityException e) {
1738                        logger.error("presignPdf ocurrio una excepcion ", e);
1739                        //e.printStackTrace();
1740                        //throw new MurachiException(e.getMessage());
1741                       
1742                        presignHash.setError(e.getMessage());
1743                        presignHash.setHash("");
1744                        return Response.status(500).entity(presignHash).build();
1745                       
1746                } 
1747               
1748                logger.debug("presignPdf: "+ presignHash.toString());
1749                return Response.status(200).entity(presignHash).build();
1750                //return presignHash;
1751                       
1752        }
1753       
1754        /**
1755         * Retorna verdadero si el archivo pdf pasado como argumento ya esta firmado.
1756         *
1757         * @param pdfReader objeto PdfReader asociado al documento pdf
1758         * @return si el archivo pdf pasado como argumento ya esta firmado.
1759         * @throws IOException
1760         */
1761        private Boolean pdfAlreadySigned(PdfReader pdfReader) throws IOException {
1762               
1763                logger.debug("pdfAlreadySigned()");
1764                Security.addProvider(new BouncyCastleProvider());
1765               
1766                AcroFields af = pdfReader.getAcroFields();
1767                ArrayList<String> names = af.getSignatureNames();
1768                if (names.size() <= 0) {
1769                        return false;
1770                }else{
1771                        return true;
1772                }
1773        }
1774       
1775        /**
1776         * Retorna el número de firmas del documento
1777         * @param pdfReader objeto PdfReader asociado al documento pdf
1778         * @return número de firmas del documento
1779         */
1780        private int numberOfSignatures(PdfReader pdfReader) {
1781                logger.debug("numberOfSignatures()");
1782                Security.addProvider(new BouncyCastleProvider());
1783               
1784                AcroFields af = pdfReader.getAcroFields();
1785                ArrayList<String> names = af.getSignatureNames();
1786                return names.size();           
1787        }
1788       
1789       
1790        /**
1791         * Ejecuta el proceso de postsign o completacion de firma de documento pdf
1792         *
1793         * @param postsignPar JSON con los parametros de postsign: signature realizada a partir
1794         * del hardware criptografico en el navegador.
1795         * @param req objeto request para crear una sesion y mantener elementos del
1796         * pdf en la misma.
1797         * @throws IOException
1798         * @throws MurachiException
1799         *
1800         *
1801         * @api {post} /Murachi/0.1/archivos/firmados/pdfs/resenas Completa la firma del documento PDF.
1802         * @apiName PdfsResenas
1803         * @apiGroup PDFS
1804         * @apiVersion 0.1.0
1805         * @apiDescription Completa la firma del documento PDF. Recibe el hash cifrado del cliente y termina de completar la firma del
1806         * archivo PDF.
1807         *
1808         * @apiSuccess {String} signedFileId Identificador único del archivo firmado en el servidor.
1809         *
1810         * @apiExample Example usage:
1811         *
1812         * $.ajax({
1813     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/pdfs/resenas",
1814     *           type: "post",
1815     *           dataType: "json",
1816     *           data: JSON.stringify({"signature":signature.hex}),
1817     *           contentType: "application/json",
1818     *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
1819     *           success: function(data, textStatus, jqXHR){
1820     *                              alert('Archivo firmado correctamente: ' + data['signedFileId']);
1821     *           },
1822         *           error: function(jqXHR, textStatus, errorThrown){
1823         *                              alert('error en pdfs/resenas: ' + textStatus);
1824         *           }
1825     *  });
1826         *
1827         *
1828         *
1829         * @apiErrorExample {json} Error-Response:
1830         *     HTTP/1.1 401 Unauthorized
1831         *     {
1832         *       "error": "acceso no autorizado"
1833         *     }
1834         *
1835         *     HTTP/1.1 500 Internal Server Error
1836         *     {
1837         *       "error": "El archivo que desea firmar no es un PDF."
1838         *     }
1839         *
1840         */
1841        @POST
1842        @Path("/pdfs/resenas")
1843        @Consumes(MediaType.APPLICATION_JSON)
1844        @Produces(MediaType.APPLICATION_JSON)
1845        @Authenticator
1846        public Response postsignPdf(PostsignParameters postsignPar, @Context HttpServletRequest req) throws IOException, MurachiException {
1847               
1848                logger.info("/pdfs/resenas");
1849               
1850                String result = "";
1851
1852                if (postsignPar == null) {
1853                       
1854                        // registrar error de firma en estadisticas
1855                        registerASignatureError(0);
1856                                               
1857                        logger.error("solicitud mal formada.");
1858                        result = "\"error\":\"solicitud mal formada\"";
1859                       
1860                        return Response.status(400).entity(result).build();     
1861                }
1862               
1863                // cadena con la firma
1864                String signature = postsignPar.getSignature();
1865                if (signature == null) {
1866                       
1867                        // registrar error de firma en estadisticas
1868                        registerASignatureError(0);
1869                       
1870                        logger.debug("signature == null");
1871                        logger.error("solicitud mal formada: no esta especificada la firma realizada en el cliente.");
1872                        result = "\"error\":\"solicitud mal formada: : no esta especificado el identificador del archivo PDF\"";
1873                        return Response.status(400).entity(result).build();
1874                }
1875                logger.debug("  signature: " + signature);
1876               
1877                HttpSession session = req.getSession(false);
1878               
1879                String fileId = (String) session.getAttribute("fileId");
1880                System.out.println("fileId: " + fileId);
1881                logger.debug("fileId: " + fileId);
1882               
1883                PdfStamper stamper = (PdfStamper) session.getAttribute("stamper");
1884               
1885                PdfPKCS7 sgn = (PdfPKCS7) session.getAttribute("sgn");
1886               
1887                byte[] hash = (byte[]) session.getAttribute("hash");
1888               
1889                Calendar cal = (Calendar) session.getAttribute("cal");
1890               
1891                PdfSignatureAppearance sap = (PdfSignatureAppearance) session.getAttribute("sap");
1892               
1893                ByteArrayOutputStream os = (ByteArrayOutputStream) session.getAttribute("baos");
1894               
1895                JSONObject jsonError = new JSONObject();
1896               
1897                if (fileId == null) {
1898                       
1899                        // registrar error de firma en estadisticas
1900                        registerASignatureError(0);                     
1901                       
1902                        System.out.println("fileId == null");
1903                        logger.error("Error en completacion de firma: identificador de archivo nulo");
1904                        //throw new MurachiException("Error en completacion de firma: estructura PdfPKCS7 nula");
1905                       
1906                        jsonError.put("error", "identificador de archivo nulo");
1907                        return Response.status(500).entity(jsonError).build();                 
1908                }
1909               
1910                if (stamper == null) {
1911                        // registrar error de firma en estadisticas
1912                        registerASignatureError(0);
1913                       
1914                        System.out.println("stamper == null");
1915                        logger.error("Error en completacion de firma: estructura PdfStamper nula");
1916                        //throw new MurachiException("Error en completacion de firma: estructura PdfPKCS7 nula");
1917                       
1918                        jsonError.put("error", "estructura PdfStamper nula");
1919                        return Response.status(500).entity(jsonError).build();                 
1920                }
1921               
1922                if (sgn == null) {
1923                        // registrar error de firma en estadisticas
1924                        registerASignatureError(0);
1925
1926                        System.out.println("sgn == null");
1927                        logger.error("Error en completacion de firma: estructura PdfPKCS7 nula");
1928                        //throw new MurachiException("Error en completacion de firma: estructura PdfPKCS7 nula");
1929                       
1930                        jsonError.put("error", "estructura PdfPKCS7 nula");
1931                        return Response.status(500).entity(jsonError).build();                 
1932                }
1933                if (hash == null) {
1934                        // registrar error de firma en estadisticas
1935                        registerASignatureError(0);
1936
1937                        System.out.println("hash == null");
1938                        logger.error("Error en completacion de firma: hash nulo");
1939                        //throw new MurachiException("Error en completacion de firma: hash nulo");
1940                        jsonError.put("error", "hash nulo");
1941                        return Response.status(500).entity(jsonError).build();
1942                }
1943                if (cal == null) {
1944                        // registrar error de firma en estadisticas
1945                        registerASignatureError(0);
1946
1947                        System.out.println("cal == null");
1948                        logger.error("Error en completacion de firma: estructura de fecha nula");
1949                        //throw new MurachiException("Error en completacion de firma: estructura de fecha nula");
1950                       
1951                        jsonError.put("error", "estructura de fecha nula");
1952                        return Response.status(500).entity(jsonError).build();
1953                }
1954                if (sap == null) {
1955                        // registrar error de firma en estadisticas
1956                        registerASignatureError(0);
1957
1958                        System.out.println("sap == null");
1959                        logger.error("Error en completacion de firma: estructura de apariencia de firma pdf nula");
1960                        //throw new MurachiException("Error en completacion de firma: estructura de apariencia de firma pdf nula");
1961                       
1962                        jsonError.put("error", "estructura de apariencia de firma pdf nula");
1963                        return Response.status(500).entity(jsonError).build();
1964                }
1965                if (os == null) {
1966                        // registrar error de firma en estadisticas
1967                        registerASignatureError(0);
1968
1969                        System.out.println("os == null");
1970                        logger.error("Error en completacion de firma: bytes de archivo nulos");
1971                        //throw new MurachiException("Error en completacion de firma: bytes de archivo nulos");
1972                       
1973                        jsonError.put("error", "bytes de archivo nulos");
1974                        return Response.status(500).entity(jsonError).build();
1975                }
1976
1977                System.out.println("antes de  hexStringToByteArray(signature)");
1978                // convertir signature en bytes         
1979                byte[] signatureInBytes = hexStringToByteArray(signature);
1980                               
1981                // completar el proceso de firma
1982                sgn.setExternalDigest(signatureInBytes, null, "RSA");
1983                byte[] encodeSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
1984                byte[] paddedSig = new byte[8192];
1985                System.arraycopy(encodeSig, 0, paddedSig, 0, encodeSig.length);
1986                PdfDictionary dic2 = new PdfDictionary();
1987                dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
1988               
1989                try {
1990                        sap.close(dic2);                       
1991                        stamper.close();
1992                        System.out.println("stamper.close");
1993                       
1994                }catch(DocumentException e) {
1995                        // registrar error de firma en estadisticas
1996                        registerASignatureError(0);
1997
1998                       
1999                        System.out.println("throw new IOException");
2000                        logger.error("postsignPdf: ocurrio una excepcion", e);
2001                        //throw new MurachiException(e.getMessage());
2002                        jsonError.put("error", e.getMessage());
2003                        return Response.status(500).entity(jsonError).build();                 
2004                       
2005                } catch (IOException e) {
2006                        // registrar error de firma en estadisticas
2007                        registerASignatureError(0);
2008
2009                        System.out.println("IOException e");
2010                        logger.error("postsignPdf: ocurrio una excepcion", e);
2011                        e.printStackTrace();
2012                        //throw new MurachiException(e.getMessage());
2013                       
2014                        jsonError.put("error", e.getMessage());
2015                        return Response.status(500).entity(jsonError).build();
2016                       
2017                }
2018               
2019                String signedPdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf";
2020               
2021                FileOutputStream signedFile = new FileOutputStream(signedPdf);
2022               
2023                os.writeTo(signedFile);
2024                os.flush();
2025                               
2026                // en este punto el archivo pdf debe estar disponible en la ruta
2027                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;             
2028                System.out.println("Archivo firmado correctamente");
2029                logger.debug("Archivo firmado correctamente");
2030                       
2031                PostsignMessage message = new PostsignMessage();
2032                //message.setMessage(SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf");
2033                message.setMessage("{\"signedFile\":"+fileId + "-signed.pdf}");
2034                //return Response.status(200).entity(message).build();
2035               
2036                JSONObject jsonFinalResult = new JSONObject();
2037                jsonFinalResult.put("signedFileId",fileId + "-signed.pdf");
2038               
2039                logger.info(jsonFinalResult.toString());
2040               
2041                // registrar la firma exitosa en el contador de firmas
2042                registerASignature(0);
2043                               
2044                return Response.status(200).entity(jsonFinalResult.toString()).build();
2045        }
2046       
2047        /**
2048         * Descarga el archivo pdf pasado como argumento.
2049         * @param idFile nombre del archivo pdf a descargar
2050         * @return archivo pdf pasado como argumento.
2051         */
2052        @GET
2053        @Path("/pdfs/{idFile}")
2054        @Authenticator
2055        public Response getPdfSigned(@PathParam("idFile") String idFile) {
2056                logger.info("/pdfs/{idFile}");
2057                File file = null;
2058               
2059                file = new File(SERVER_UPLOAD_LOCATION_FOLDER + idFile);
2060                /*
2061                if (!file.exists()){
2062                       
2063                }
2064                */
2065                         
2066                ResponseBuilder response = Response.ok((Object) file);
2067                response.header("Content-Disposition", "attachment; filename=" + file.getName());
2068                return response.build();
2069        }
2070       
2071        // ************************************************************************
2072        // ************************************************************************
2073        // ************************************************************************
2074        // ************************************************************************
2075        // ************************************************************************
2076        // ************************************************************************
2077        // ************************************************************************
2078        // *********************************BDOC***********************************
2079       
2080        /**
2081         * Retorna un JSON con informacion de las firmas del documento BDOC
2082         * @param bdocFile archivo BDOC a verificar
2083         * @param serialized verdadero si el contenedor a verificar esta serializado
2084         * @return JSON con informacion de las firmas del documento BDOC
2085         */
2086        private JSONObject verifySignaturesInBdoc(String bdocFile, Boolean serialized) {
2087       
2088                logger.debug("verifySignaturesInBdoc("+bdocFile+")");
2089                System.out.println("verifySignaturesInBdoc(String bdocFile)");
2090               
2091                JSONObject jsonSignatures = new JSONObject();
2092
2093                JSONArray jsonSignaturesArray = new JSONArray();
2094                JSONArray jsonContainerValidationExceptionArray = new JSONArray();
2095               
2096                java.nio.file.Path path = Paths.get(bdocFile);
2097                String idFile = path.getFileName().toString();
2098               
2099                Container container = null;
2100               
2101                Configuration configuration = new Configuration(Configuration.Mode.PROD);
2102               
2103                configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
2104               
2105                configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
2106                try
2107                {
2108                        Security.addProvider(new BouncyCastleProvider());
2109                        if (!serialized) 
2110                        {
2111                                container = Container.open(bdocFile, configuration);
2112                                logger.debug("Container.open("+bdocFile+", DIGIDOC4J_CONFIGURATION)"); 
2113                        }
2114                        else
2115                        {
2116                                container = deserialize(bdocFile);
2117                                logger.debug("container deserialized: " + bdocFile);
2118                        }
2119                                               
2120                } catch(DigiDoc4JException e) 
2121                {
2122                        jsonSignatures.put("error", "File is not a valid BDOC container");
2123                        return jsonSignatures;
2124                } catch (ClassNotFoundException e) {
2125                        jsonSignatures.put("error", "error al deserializar el contendor");
2126                        return jsonSignatures;
2127                } catch (IOException e) {
2128                        jsonSignatures.put("error", "error al deserializar el contendor");
2129                        return jsonSignatures;
2130                }
2131               
2132               
2133                int numberOfSignatures = container.getSignatures().size();
2134                if (numberOfSignatures == 0){
2135                        jsonSignatures.put("signatureNumber", "0");
2136                        System.out.println("signatureNumber: 0");
2137                }else{
2138                        jsonSignatures.put("fileExist", "true");
2139                        System.out.println("fileExist: true");
2140                                               
2141                        if (serialized){
2142                                jsonSignatures.put("fileId", idFile.split("-serialized.bin")[0]);
2143                        }
2144                        else {
2145                                jsonSignatures.put("fileId", idFile);
2146                        }
2147                       
2148                        jsonSignatures.put("mimeType", "application/vnd.etsi.asic-e+zip");
2149                       
2150                        // informacion de archivos dentro del contenedor
2151                        if (container.getDataFiles().size() > 0){
2152                                jsonSignatures.put("numberOfDataFiles", container.getDataFiles().size()); 
2153                                jsonSignatures.put("dataFiles", getJSONFromBDOCDataFiles(container.getDataFiles()));
2154                                System.out.println(" dataFiles:  " + getJSONFromBDOCDataFiles(container.getDataFiles()).toString());
2155                        }else{
2156                                System.out.println(" dataFiles:  == 0");
2157                        }
2158               
2159                        jsonSignatures.put("numberOfSignatures", numberOfSignatures);
2160                       
2161                        System.out.println("->container.validate()");
2162                        ValidationResult validationResult = container.validate();
2163                        System.out.println("...container.validate()");
2164                       
2165                       
2166                        List<DigiDoc4JException> exceptions = validationResult.getContainerErrors();
2167                        System.out.println("...validationResult.getContainerErrors()");
2168                       
2169                        boolean isDDoc = container.getDocumentType() == DocumentType.DDOC;
2170                       
2171                        if (exceptions.size() > 0){
2172                                jsonSignatures.put("containerValidation", false);
2173                               
2174                                for (DigiDoc4JException exception : exceptions) {
2175                                        JSONObject containerException = new JSONObject();
2176                                       
2177                                        if (isDDoc && isWarning(((DDocContainer) container).getFormat(), exception)){
2178                                                System.out.println("    Warning: " + exception.toString());
2179                                               
2180                                    }
2181                                    else{
2182                                        System.out.println((isDDoc ? "  " : "   Error_: ") + exception.toString());
2183                                       
2184                                    }
2185                                        containerException.put("containerValidationException", exception.toString());
2186                                    jsonContainerValidationExceptionArray.put(containerException);
2187                                }
2188                            if (isDDoc && (((ValidationResultForDDoc) validationResult).hasFatalErrors())) {
2189                                jsonSignatures.put("validationResultForDDocHasFatalErrors", true);
2190                                return jsonSignatures; 
2191                            }
2192                            jsonSignatures.put("containerValidationExceptions", jsonContainerValidationExceptionArray);
2193                               
2194                               
2195                        }else{
2196                                jsonSignatures.put("containerValidation", true);
2197                               
2198                                HashMap<String, String> signatureInformation;
2199                                for (int i=0; i< numberOfSignatures; i++) {
2200                                        System.out.println("===== firma " + i + " =====");
2201                                        signatureInformation = verifyBDOCSignature(container.getSignature(i), container.getDocumentType());
2202                                        System.out.println("signatureInformation.size " + signatureInformation.size());
2203                                       
2204                                        JSONObject jo = getJSONFromASignature(signatureInformation);
2205                                        //System.out.println("jo:  " + jo.toString());
2206                                        jsonSignaturesArray.put(jo);                                   
2207                                }
2208                                                               
2209                                jsonSignatures.put("signatures", jsonSignaturesArray);                                                         
2210                                System.out.println(jsonSignatures.toString());                         
2211                        }                       
2212                }
2213                //verifyBdocContainer(container);               
2214                //jsonSignatures.put("validation", "executed");                         
2215                return jsonSignatures;
2216        }
2217       
2218        /**
2219         * Retorna un JSON con informacion de las firmas del documento BDOC
2220         * @param serializedBDOC archivo BDOC serializado
2221         * @return JSON con informacion de las firmas del documento BDOC
2222         */
2223        private JSONObject getSignaturesInformation(Container container) {
2224       
2225                logger.debug("getSignaturesInformation()");
2226                System.out.println("getSignaturesInformation()");
2227               
2228                JSONObject jsonSignatures = new JSONObject();
2229
2230                JSONArray jsonSignaturesArray = new JSONArray();
2231                JSONArray jsonContainerValidationExceptionArray = new JSONArray();
2232               
2233                //java.nio.file.Path path = Paths.get(serializedBDOC);
2234                //String idFile = path.getFileName().toString();
2235               
2236               
2237                Security.addProvider(new BouncyCastleProvider());
2238                //Container container = null;
2239               
2240                Configuration configuration = new Configuration(Configuration.Mode.PROD);
2241               
2242                configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
2243               
2244                configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
2245                /*
2246                try
2247                {
2248                        //container = Container.open(serializedBDOC, configuration);
2249                        //logger.debug("Container.open("+serializedBDOC+", DIGIDOC4J_CONFIGURATION)");
2250                        container = deserialize();
2251                       
2252                       
2253                } catch(DigiDoc4JException e)
2254                {
2255                        jsonSignatures.put("error", "File is not a valid BDOC container");
2256                        return jsonSignatures;
2257                }
2258                */
2259               
2260                int numberOfSignatures = container.getSignatures().size();
2261                if (numberOfSignatures == 0){
2262                        jsonSignatures.put("signatureNumber", "0");
2263                        System.out.println("signatureNumber: 0");
2264                }else{
2265                        //jsonSignatures.put("fileExist", "true");
2266                        //System.out.println("fileExist: true");
2267                       
2268                        //jsonSignatures.put("fileId", idFile);
2269                        //jsonSignatures.put("mimeType", "application/vnd.etsi.asic-e+zip");
2270                       
2271                        /*
2272                        // informacion de archivos dentro del contenedor
2273                        if (container.getDataFiles().size() > 0){
2274                                jsonSignatures.put("numberOfDataFiles", container.getDataFiles().size());
2275                                jsonSignatures.put("dataFiles", getJSONFromBDOCDataFiles(container.getDataFiles()));
2276                                System.out.println(" dataFiles:  " + getJSONFromBDOCDataFiles(container.getDataFiles()).toString());
2277                        }else{
2278                                System.out.println(" dataFiles:  == 0");
2279                        }
2280                        */
2281               
2282                        jsonSignatures.put("numberOfSignatures", numberOfSignatures);
2283                       
2284                        System.out.println("->container.validate()");
2285                        ValidationResult validationResult = container.validate();
2286                        System.out.println("...container.validate()");
2287                       
2288                       
2289                        List<DigiDoc4JException> exceptions = validationResult.getContainerErrors();
2290                        System.out.println("...validationResult.getContainerErrors()");
2291                       
2292                        boolean isDDoc = container.getDocumentType() == DocumentType.DDOC;
2293                       
2294                        if (exceptions.size() > 0){
2295                                jsonSignatures.put("containerValidation", false);
2296                               
2297                                for (DigiDoc4JException exception : exceptions) {
2298                                        JSONObject containerException = new JSONObject();
2299                                       
2300                                        if (isDDoc && isWarning(((DDocContainer) container).getFormat(), exception)){
2301                                                System.out.println("    Warning: " + exception.toString());
2302                                               
2303                                    }
2304                                    else{
2305                                        System.out.println((isDDoc ? "  " : "   Error_: ") + exception.toString());
2306                                       
2307                                    }
2308                                        containerException.put("containerValidationException", exception.toString());
2309                                    jsonContainerValidationExceptionArray.put(containerException);
2310                                }
2311                            if (isDDoc && (((ValidationResultForDDoc) validationResult).hasFatalErrors())) {
2312                                jsonSignatures.put("validationResultForDDocHasFatalErrors", true);
2313                                return jsonSignatures; 
2314                            }
2315                            jsonSignatures.put("containerValidationExceptions", jsonContainerValidationExceptionArray);
2316                               
2317                               
2318                        }else{
2319                                jsonSignatures.put("containerValidation", true);
2320                               
2321                                HashMap<String, String> signatureInformation;
2322                                for (int i=0; i< numberOfSignatures; i++) {
2323                                        System.out.println("===== firma " + i + " =====");
2324                                        signatureInformation = verifyBDOCSignature(container.getSignature(i), container.getDocumentType());
2325                                        System.out.println("signatureInformation.size " + signatureInformation.size());
2326                                       
2327                                        JSONObject jo = getJSONFromASignature(signatureInformation);
2328                                        //System.out.println("jo:  " + jo.toString());
2329                                        jsonSignaturesArray.put(jo);                                   
2330                                }
2331                                                               
2332                                jsonSignatures.put("signatures", jsonSignaturesArray);                                                         
2333                                System.out.println(jsonSignatures.toString());                         
2334                        }                       
2335                }
2336               
2337                return jsonSignatures;
2338        }
2339       
2340       
2341        /**
2342         * Retorna un JSON con informacion de los DataFiles incluidos en el contenedor
2343         * @param dataFilesList lista de DataFile incluidos en el contenedor
2344         * @return JSON con informacion de los DataFiles incluidos en el contenedor
2345         */
2346        private JSONArray getJSONFromBDOCDataFiles(List<DataFile> dataFilesList) {
2347               
2348                System.out.println("getJSONFromBDOCDataFiles(List<DataFile> dataFilesList)");
2349                logger.debug("getJSONFromBDOCDataFiles(List<DataFile> dataFilesList)");
2350               
2351                JSONArray jsonDataFileArray = new JSONArray();
2352               
2353                for (int i = 0; i < dataFilesList.size(); i++){
2354                       
2355                        JSONObject tmpJsonDataFile = new JSONObject();
2356                        DataFile df = dataFilesList.get(i);
2357                        System.out.println("...dataFilesList.get(i)");
2358                                               
2359                        tmpJsonDataFile.put("dataFileSize", Long.toString(df.getFileSize()));
2360                        logger.debug("dataFileSize: " + Long.toString(df.getFileSize()));
2361                       
2362                        tmpJsonDataFile.put("filename", df.getId());
2363                        logger.debug("filename: " + df.getId());
2364                       
2365                        tmpJsonDataFile.put("mediaType", df.getMediaType());
2366                        logger.debug("mediaType: " + df.getMediaType());
2367                       
2368                        tmpJsonDataFile.put("name", df.getName());
2369                        logger.debug("name: " + df.getName());
2370                       
2371                        jsonDataFileArray.put(tmpJsonDataFile);
2372                }
2373               
2374                //JSONObject jsonDataFile = new JSONObject();
2375                //jsonDataFile.put("dataFiles", jsonDataFileArray);
2376               
2377                //return jsonDataFile;
2378                System.out.println("...saliendo");
2379                return jsonDataFileArray;
2380        }
2381
2382        /**
2383         * Retorna Hashmap con la informacion de una firma electronica que se verifica
2384         * @param signature firma para verificar
2385         * @param documentType tipo de documento
2386         * @return Hashmap con la informacion de una firma electronica que se verifica
2387         */
2388        private static HashMap<String, String> verifyBDOCSignature(Signature signature, DocumentType documentType) {
2389                logger.debug("verifyBDOCSignature(Signature signature, DocumentType documentType)");
2390               
2391                HashMap<String, String> signatureMap = new HashMap<String, String>();
2392               
2393                boolean isDDoc = documentType == DocumentType.DDOC;
2394               
2395                List<DigiDoc4JException> signatureValidationResult = signature.validate();
2396               
2397                if (signatureValidationResult.size() > 0) {
2398                        System.out.println("Signature " + signature.getId() + " is not valid");
2399                signatureMap.put("isValid", Boolean.toString(false));
2400               
2401                logger.debug("Signature " + signature.getId() + " is not valid");
2402               
2403                int counter = 1;
2404               
2405                //JSONArray jsonValidationExceptionArray = new JSONArray();
2406                //JSONObject tmpValidationException = new JSONObject();
2407               
2408                for (DigiDoc4JException exception : signatureValidationResult) {
2409                  System.out.println((isDDoc ? "        " : "   Error: ") + exception.toString());
2410                  signatureMap.put("signature"+signature.getId()+"ValidationException"+counter, exception.toString());
2411                 
2412                  //tmpValidationException.put("ValidationException", exception.toString());             
2413                  //jsonValidationExceptionArray.put(tmpValidationException);
2414                }
2415                //signatureMap.put("validationException", jsonValidationExceptionArray);
2416             
2417              if (isDDoc && isDDocTestSignature(signature)) {
2418                System.out.println("Signature " + signature.getId() + " is a test signature");
2419                signatureMap.put("isDDocTestSignature", Boolean.toString(true));
2420              }
2421                }
2422                else{                   
2423                        System.out.println("Signature " + signature.getId() + " is valid");
2424                        logger.debug("Signature " + signature.getId() + " is valid");
2425                signatureMap.put("isValid", Boolean.toString(true));           
2426                }
2427                signatureMap.put("signatureId", signature.getId());
2428        signatureMap.put("signatureProfile", signature.getProfile().toString());
2429        signatureMap.put("signatureMethod", signature.getSignatureMethod());
2430        /*
2431        if (signature.getSignerRoles().size() > 0){             
2432                signatureMap.put("signerRole1", signature.getSignerRoles().get(0));
2433                if (signature.getSignerRoles().size() == 2){
2434                        signatureMap.put("signerRole2", signature.getSignerRoles().get(1));
2435                }
2436        }
2437        */
2438        signatureMap.put("signatureCity", signature.getCity());
2439        signatureMap.put("signatureState", signature.getStateOrProvince());
2440        signatureMap.put("signaturePostalCode", signature.getPostalCode());
2441        signatureMap.put("signatureCountry", signature.getCountryName());
2442        signatureMap.put("signatureSigningTime", signature.getSigningTime().toString());
2443        //signatureMap.put("signaturePolicy", signature.getPolicy());
2444        //signatureMap.put("signatureOCSPProducedAtTimestamp", signature.getProducedAt().toString());
2445        //signatureMap.put("signaturePolicyURI", signature.getSignaturePolicyURI().toString());
2446        //signatureMap.put("signatureTimestampGenerationTime", signature.getTimeStampCreationTime().toString());
2447               
2448       
2449        X509Cert signerCertificate = signature.getSigningCertificate();
2450        signatureMap.put("signerCertificateSerial", signerCertificate.getSerial());
2451        signatureMap.put("signerCertificateSubjectName", signerCertificate.getSubjectName());
2452        signatureMap.put("signerCertificateIssuer", signerCertificate.issuerName());
2453        if (signerCertificate.isValid()){
2454                signatureMap.put("signerCertificateIsValid", Boolean.toString(true));
2455        }else{
2456                signatureMap.put("signerCertificateIsValid", Boolean.toString(false));
2457        }
2458               
2459                return signatureMap;
2460        }
2461       
2462        // ************************************************************************
2463        // ************************************************************************
2464        // ************************************************************************
2465        // ****************************RECURSOS BDOC*******************************
2466       
2467        /**
2468         * Ejecuta el proceso de presign o preparacion de firma de un archivo en formato BDOC.
2469         *
2470         * Estructura del JSON que recibe la funcion:
2471         *
2472         *      {"fileId":"file_id",
2473         *      "certificate":"hex_cert_value",
2474         *  "city":"ciudad",
2475         *  "state":"estado",
2476         *  "postalCode":"codigoPostal",
2477         *  "country":"pais",
2478         *  "role":"rol",
2479         *  "addSignature":true/false
2480         *  }
2481         *
2482         *
2483         * @param presignPar JSON con los parametros de preparacion: Id del archivo, certificado, ciudad, estado, codigoPostal, país, rol.
2484         *
2485         * @param req objeto request para crear una sesion y mantener elementos del BDOC
2486         *  en la misma.
2487         *
2488         * @throws MurachiException
2489         *
2490         * @api {post} /Murachi/0.1/archivos/firmados/bdocs Prepara la firma de un archivo en formato BDOC.
2491         * @apiName BDocs
2492         * @apiGroup BDOCS
2493         * @apiVersion 0.1.0
2494         * @apiDescription Prepara la firma de un archivo en formato BDOC. Se debe pasar un JSON con la siguiente estructura:
2495         *
2496         * {"fileId":"file_id", "certificate":"hex_cert_value",
2497         * "city":"ciudad", "state":"estado", "postalCode":"codigoPostal",
2498         * "country":"pais", "role":"rol", "addSignature":true/false
2499         * }
2500         * 
2501         *  fileId: corresponde al identificador del archivo que se encuentra en el servidor y se desea firmar.
2502         * 
2503         *  certificate: corresponde al certificado del firmante en formato hexadecimal.
2504         * 
2505         *  city: corresponde a la ciudad en la que se realiza la firma.
2506         * 
2507         *  state: corresponde al estado en el que se reailza la firma.
2508         * 
2509         *  postalCode: corresponde al código postal del lugar donde se realiza la firma.
2510         * 
2511         *  country: corresponde al país donde se realiza la firma.
2512         * 
2513         *  role: corresponde al rol del firmante.
2514         * 
2515         *  addSignature: true si se debe agregar una firma a un contenedor BDOC existente; false si se debe crear
2516         *  un contenedor nuevo para firmar.
2517         *
2518         * @apiSuccess {String} hash Reseña o hash del archivo que se debe cifrar con la clave privada protegida por el
2519         * dispositivo criptográfico.
2520         *
2521         * @apiExample Example usage:
2522         *
2523         * var parameters = JSON.stringify({
2524         *                             "fileId":fileId,
2525         *                             "certificate":cert.hex,
2526         *                             "city":"Merida",
2527     *                             "state":"Merida",
2528         *                             "postalCode":"5101",
2529         *                             "country":"Venezuela",
2530         *                             "role":"Desarrollador",
2531         *                             "addSignature":true
2532         *                             });
2533         *
2534         * $.ajax({
2535     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs",
2536     *           type: "post",
2537     *           dataType: "json",
2538     *           data: parameters,
2539     *           contentType: "application/json",
2540     *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
2541     *           success: function(data, textStatus, jqXHR){
2542         *                              var json_x = data;
2543     *                              var hash = json_x['hash'];
2544     *                              alert("hash recibido del servidor "+hash);
2545     *           },
2546         *           error: function(jqXHR, textStatus, errorThrown){
2547         *                              //alert('error: ' + textStatus);
2548         *                              //var responseText = jQuery.parseJSON(jqXHR.responseText);
2549         *                              alert('ajax error function: ' + jqXHR.responseText);
2550         *                             
2551         *           }
2552     *  });
2553         *
2554         *
2555         *
2556         * @apiErrorExample {json} Error-Response:
2557         *     HTTP/1.1 401 Unauthorized
2558         *     {
2559         *       "error": "acceso no autorizado"
2560         *     }
2561         *     
2562         *     HTTP/1.1 500 Internal Server Error
2563         *     {
2564         *       "hash": "",
2565         *       "error": "Error en el certificado del firmante"
2566         *     }
2567         *
2568         *
2569         */
2570        @POST
2571        @Path("/bdocs")
2572        @Consumes(MediaType.APPLICATION_JSON)
2573        @Produces(MediaType.APPLICATION_JSON)
2574        @Authenticator
2575        public Response presignBdoc(PresignParametersBdoc presignPar, @Context HttpServletRequest req) throws MurachiException {
2576               
2577                logger.info("/bdocs");
2578               
2579                PresignHash presignHash = new PresignHash();
2580
2581                // obtener el id del archivo a firmaer
2582                String fileId = presignPar.getFileId();
2583               
2584                // cadena con el certificado
2585                String certHex = presignPar.getCertificate();
2586                System.out.println("certificado en Hex: " + certHex);
2587
2588                String city = presignPar.getCity();
2589                logger.debug("city: " + city);
2590               
2591                String state = presignPar.getState();
2592                logger.debug("state: " + state);
2593               
2594                String postalCode = presignPar.getPostalCode();
2595                logger.debug("postalCode: " + postalCode);
2596               
2597                String country = presignPar.getCountry();
2598                logger.debug("country: " + country);
2599               
2600                String role = presignPar.getRole();
2601                logger.debug("role: " + role);
2602               
2603                Boolean addSignature = presignPar.getAddSignature();
2604                logger.debug("addSignature: " + addSignature.toString());
2605               
2606                CertificateFactory cf;
2607                X509Certificate signerCert;
2608               
2609                //
2610                String hashToSign = "";
2611                               
2612               
2613                SignedInfo signedInfo;
2614               
2615                fileId = presignPar.getFileId();
2616                String sourceFile = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
2617                System.out.println("archivo a firmar: " + sourceFile);
2618                logger.debug("archivo a firmar: " + sourceFile);
2619               
2620                String sourceFileMimeType = getMimeTypeWithTika(sourceFile);
2621                logger.debug("mimeType del archivo a firmar: " + sourceFileMimeType);
2622               
2623                certHex = presignPar.getCertificate();
2624                System.out.println("certificado en Hex: " + certHex);
2625                logger.debug("certificado firmante en Hex: " + certHex);
2626               
2627                try
2628                {
2629                        Security.addProvider(new BouncyCastleProvider());
2630                        Container container = null;
2631               
2632                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
2633               
2634                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
2635               
2636                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
2637       
2638                        // se debe agregar una firma al contenedor existente
2639                        if (addSignature)
2640                        {
2641                                container = Container.open(sourceFile, configuration);
2642                                logger.debug("open container: "+ sourceFile);
2643                        }
2644                        else // crear un contenedor nuevo
2645                        {
2646                                container = Container.create(Container.DocumentType.BDOC, configuration);
2647                                logger.debug("container created");
2648                                container.addDataFile(sourceFile, sourceFileMimeType);
2649                                logger.debug("container addDataFile");
2650                        }
2651                       
2652               
2653                        SignatureParameters signatureParameters = new SignatureParameters();
2654                        SignatureProductionPlace productionPlace = new SignatureProductionPlace();
2655                        productionPlace.setCity(city);
2656                        productionPlace.setStateOrProvince(state);
2657                        productionPlace.setPostalCode(postalCode);
2658                        productionPlace.setCountry(country);
2659                        signatureParameters.setProductionPlace(productionPlace);
2660                        logger.debug("container setProductionPlace");
2661                        signatureParameters.setRoles(asList(role));
2662                        container.setSignatureParameters(signatureParameters);
2663                        container.setSignatureProfile(SignatureProfile.B_BES);
2664               
2665                       
2666               
2667                        cf = CertificateFactory.getInstance("X.509");
2668               
2669                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
2670               
2671                        signerCert = (X509Certificate) cf.generateCertificate(in);
2672               
2673                        signedInfo = container.prepareSigning(signerCert);
2674               
2675                        hashToSign = byteArrayToHexString(signedInfo.getDigest());
2676               
2677                        System.out.println("presignBdoc - hash: " + hashToSign);
2678                        logger.debug("hash to sign: " + hashToSign);
2679               
2680                        // establecer el nombre del archivo a serializar
2681                        String serializedContainerId = sourceFile + "-serialized";
2682               
2683                        // serializar el archivo
2684                        serialize(container, serializedContainerId);
2685                               
2686                        // almacenar los objetos necesarios para realizar el postsign en una sesion
2687                        HttpSession session = req.getSession(true);
2688                        session.setAttribute("hashToSign", hashToSign);                         
2689                        session.setAttribute("fileId", fileId);
2690                        session.setAttribute("serializedContainerId", serializedContainerId);           
2691                } catch(IOException e)
2692                {
2693                        // registrar error de firma en estadisticas
2694                        registerASignatureError(1);
2695                       
2696                        presignHash.setError(e.getMessage());
2697                        presignHash.setHash("");
2698                        return Response.status(500).entity(presignHash).build();
2699                } catch(CertificateException e)
2700                {
2701                        // registrar error de firma en estadisticas
2702                        registerASignatureError(1);
2703
2704                        presignHash.setError(e.getMessage());
2705                        presignHash.setHash("");
2706                        return Response.status(500).entity(presignHash).build();
2707                }
2708                                               
2709                // creacion del json
2710                JSONObject jsonHash = new JSONObject();
2711                jsonHash.put("hashToSign", hashToSign);
2712
2713                presignHash.setHash(hashToSign);
2714                presignHash.setError("");               
2715               
2716                logger.debug("presignBdoc: "+ presignHash.toString());
2717                return Response.status(200).entity(presignHash).build();                       
2718        }
2719       
2720       
2721       
2722        /**
2723         * Ejecuta el proceso de postsign o completacion de firma de archivo en formato BDOC.
2724         *
2725         * @param postsignPar JSON con los parametros de postsign: signature realizada a partir
2726         * del hardware criptografico en el navegador.
2727         *
2728         * @param req objeto request para crear una sesion y mantener elementos del
2729         * BDOC en la misma.
2730         *
2731         * @throws IOException
2732         * @throws MurachiException
2733         *
2734         *
2735         * @api {post} /Murachi/0.1/archivos/firmados/bdocs/resenas Completa la firma del archivo en formato BDOC.
2736         * @apiName BdocResenas
2737         * @apiGroup BDOCS
2738         * @apiVersion 0.1.0
2739         * @apiDescription Completa la firma del archivo en formato BDOC. Recibe el hash cifrado del cliente y termina de completar la firma del
2740         * archivo en formato BDOC.
2741         *
2742         * @apiSuccess {String} signedFileId Identificador único del archivo firmado en el servidor.
2743         *
2744         * @apiExample Example usage:
2745         *
2746         * $.ajax({
2747     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/resenas",
2748     *           type: "post",
2749     *           dataType: "json",
2750     *           data: JSON.stringify({"signature":signature.hex}),
2751     *           contentType: "application/json",
2752     *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
2753     *           success: function(data, textStatus, jqXHR){
2754     *                              alert('Archivo firmado correctamente: ' + data['signedFileId']);
2755     *           },
2756         *           error: function(jqXHR, textStatus, errorThrown){
2757         *                              alert('error en pdfs/resenas: ' + textStatus);
2758         *           }
2759     *  });
2760         *
2761         *
2762         *
2763         * @apiErrorExample {json} Error-Response:
2764         *     HTTP/1.1 401 Unauthorized
2765         *     {
2766         *       "error": "acceso no autorizado"
2767         *     }
2768         *     
2769         *     HTTP/1.1 500 Internal Server Error
2770         *     {
2771         *       "error": "Error en proceso de deserialización y completación de firma"
2772         *     }
2773         *
2774         */
2775        @POST
2776        @Path("/bdocs/resenas")
2777        @Consumes(MediaType.APPLICATION_JSON)
2778        @Produces(MediaType.APPLICATION_JSON)
2779        @Authenticator
2780        public Response postsignBdoc(PostsignParameters postsignPar, @Context HttpServletRequest req) throws IOException, MurachiException {
2781               
2782                logger.info("/bdocs/resenas");
2783
2784                // cadena con la firma
2785                String signature = postsignPar.getSignature();
2786                System.out.println("firma en Hex: " + signature);
2787                logger.info("firma en Hex: " + signature);
2788               
2789                HttpSession session = req.getSession(false);
2790               
2791                String fileId = (String) session.getAttribute("fileId");
2792                System.out.println("fileId: " + fileId);
2793                logger.debug("fileId: " + fileId);
2794               
2795                String serializedContainerId = (String) session.getAttribute("serializedContainerId") + ".bin";
2796                               
2797                System.out.println("serializedContainerId: " + serializedContainerId);
2798                logger.debug("serializedContainerId: " + serializedContainerId);
2799               
2800                String signedBdoc = SERVER_UPLOAD_LOCATION_FOLDER + fileId + ".bdoc";
2801               
2802                try {
2803                        Container deserializedContainer = deserialize(serializedContainerId);
2804                       
2805                        byte[] signatureInBytes = hexStringToByteArray(signature);
2806                       
2807                        deserializedContainer.signRaw(signatureInBytes);
2808                        deserializedContainer.save(signedBdoc);
2809                        logger.debug("archivo firmado escrito en: " + signedBdoc);                     
2810                } catch (ClassNotFoundException e) {
2811                        //e.printStackTrace();
2812                       
2813                        // registrar error de firma en estadisticas
2814                        registerASignatureError(1);
2815                       
2816                        JSONObject jsonError = new JSONObject();
2817                                               
2818                        System.out.println("ClassNotFoundException e: " + e.getMessage());
2819                        logger.error("error: " + e.getMessage());
2820                                                       
2821                        jsonError.put("error", e.getMessage());
2822                        return Response.status(500).entity(jsonError).build();                         
2823                }
2824                               
2825                // en este punto el archivo bdoc debe estar disponible en la ruta
2826                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;             
2827                System.out.println("Archivo firmado correctamente");
2828                logger.debug("Archivo firmado correctamente");
2829                       
2830                PostsignMessage message = new PostsignMessage();
2831                message.setMessage("{\"signedFile\":"+fileId + ".bdoc}");
2832                               
2833                JSONObject jsonFinalResult = new JSONObject();
2834                jsonFinalResult.put("signedFileId",fileId + ".bdoc");
2835               
2836                logger.info(jsonFinalResult.toString());
2837               
2838                // registrar la firma exitosa en el contador de firmas
2839                //MURACHIStatistic statistic = new MURACHIStatistic(databaseHost, databasePort, databaseName, databaseLogin, databasePassword);
2840                //statistic.incrementSignatures(1);             
2841                registerASignature(1);
2842               
2843                return Response.status(200).entity(jsonFinalResult.toString()).build();
2844        }
2845       
2846       
2847        // ********************************************************************************
2848        // ********************************************************************************
2849        // ********************************************************************************
2850        // revision de recursos para que cada uno de ellos realice operaciones sobre un
2851        // contenendor BDOC y siempre finalice con el contenedor serializado en el sistema
2852        // de archivos
2853        // ********************************************************************************
2854        // ********************************************************************************
2855        // ********************************************************************************
2856       
2857               
2858        /**
2859         * Crea un contenedor BDOC con los archivos subidos del formulario, lo serializa y
2860         * retorna el identificados unico del contenedor.
2861         *
2862         * @param formParams parametros del formulario.
2863         * 
2864         * @return  identificador unico del contenedor creado.
2865         *
2866         *
2867         * @api {post} /Murachi/0.1/archivos/bdocs/cargas Crea un contenedor BDOC.
2868         * @apiName BDocCargas
2869         * @apiGroup BDOCS
2870         * @apiVersion 0.1.0
2871         * @apiDescription Crea un contenedor BDOC con los archivos subidos
2872         * a través del formulario, serializa el contenedor y retorna el identificador único del mismo.
2873         *
2874         * @apiSuccess {String} containerId Identificador único del contenedor BDOC creado.
2875         *
2876         * @apiExample Example usage:
2877         *
2878         * var formData = new FormData();
2879     * var fileInput = document.getElementById("file-sign");
2880     * var list = fileInput.files;
2881     * for (var i=0; i<list.length; i++){
2882         *    formData.append("upload", $("#file-sign")[0].files[i]);
2883         * }
2884         *
2885         * $.ajax({
2886     *          url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/cargas",
2887     *          type: "post",
2888     *          dataType: "json",
2889     *          data: formData,
2890     *          cache: false,
2891     *          contentType: false,
2892         *          processData: false,
2893         *          headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
2894         *          success: function(response) {
2895         *             var fileId = response.containerId.toString();
2896         *          },
2897         *          error: function(jqXHR, textStatus, errorThrown){
2898         *             alert('ajax error function: ' + jqXHR.responseText);                             
2899         *          }
2900     *  });
2901     * 
2902         * @apiErrorExample {json} Error-Response:
2903         *     HTTP/1.1 401 Unauthorized
2904         *     {
2905         *       "error": "acceso no autorizado"
2906         *     }
2907         *
2908         *     HTTP/1.1 500 Internal Server Error
2909         *     {
2910         *       "error": "no se pudo crear el contenedor; falló la serialización."
2911         *     }
2912         *
2913         */
2914        @POST
2915        @Path("/bdocs/cargas")
2916        @Consumes(MediaType.MULTIPART_FORM_DATA)
2917        @Produces(MediaType.APPLICATION_JSON)
2918        @Authenticator
2919        public Response uploadFilesToBDOC(FormDataMultiPart formParams) throws MurachiException {
2920               
2921                logger.info("recurso /bdocs/cargas");
2922                logger.debug("  uploadFilesToBDOC...");
2923               
2924                // cadena con la respuesta
2925                String result = "";
2926               
2927                if (formParams == null) {
2928                        logger.error("solicitud mal formada.");
2929                        result = "\"error\":\"solicitud mal formada\"";
2930                        return Response.status(400).entity(result).build();
2931                }
2932               
2933                Security.addProvider(new BouncyCastleProvider());               
2934                Container c = createBDOCContainer();
2935                logger.debug("  creado contenedor");
2936               
2937                Map<String, List<FormDataBodyPart>> fieldsByName = formParams.getFields();
2938                logger.debug("  contenido de Map: " + Integer.toString(fieldsByName.size()));
2939               
2940                for (List<FormDataBodyPart> fields : fieldsByName.values())
2941            {
2942                for (FormDataBodyPart field : fields)
2943                {
2944                    InputStream is = field.getEntityAs(InputStream.class);
2945                   
2946                    if (is == null) 
2947                    {
2948                        // registrar error de firma en estadisticas
2949                                registerASignatureError(1);
2950                               
2951                        logger.debug("is: null");
2952                        result = "\"error\":\"archivo pasado al recurso es nulo.\"";
2953                                return Response.status(500).entity(result).build();
2954                    }             
2955                   
2956                    FormDataContentDisposition file = field.getFormDataContentDisposition();               
2957                    String fileName = file.getFileName();
2958                    logger.debug("fileName: " + fileName);                 
2959                   
2960                    if (fileName == null)
2961                    {
2962                        logger.debug("fileName: null");
2963                        result = "\"error\":\"nombre del archivo pasado al recurso es nulo. Debe especificar un nombre de archivo.\"";
2964                                return Response.status(500).entity(result).build();
2965                    }               
2966                   
2967                    String mimeType = field.getMediaType().toString();                             
2968                    logger.debug("mimeType: " + mimeType);
2969                   
2970                    if (mimeType == null)
2971                    {
2972                        logger.debug("mimeType: null");
2973                        result = "\"error\":\"tipo mime del archivo pasado al recurso es nulo.\"";
2974                                return Response.status(500).entity(result).build();
2975                    }
2976                                                   
2977                    try
2978                    {
2979                        addFileToBDOCContainer(is, fileName, mimeType, c);
2980                    }
2981                    catch(Exception e) 
2982                    {
2983                        logger.debug("excepcion: " + e.getMessage());                   
2984                                result = "\"error\":\"no se pudo insertar el archivo al contenedor.\"";
2985                                return Response.status(500).entity(result).build();
2986                    }               
2987                                   
2988                }
2989            }           
2990               
2991                logger.debug("cantidad de DataFile del contenedor: " + Integer.toString(c.getDataFiles().size()));
2992                String fileId = UUID.randomUUID().toString();
2993                System.out.println("id contenedor serializado: "+fileId);
2994                               
2995                // establecer el nombre del archivo a serializar
2996                String serializedContainerId = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-serialized";
2997                logger.debug("  id de contenedor serializado: "+ serializedContainerId);
2998       
2999                // serializar el archivo
3000                try {
3001                        serialize(c, serializedContainerId);
3002                } catch (IOException e1) {
3003                        logger.error("error en la serializacion del contendor");
3004                        e1.printStackTrace();
3005                       
3006                        result = "error al serializar el archivo"+fileId;
3007                        result = "\"error\":\"no se pudo crear el contenedor; falló la serialización.\"";
3008                        return Response.status(500).entity(result).build();
3009                }
3010                result = "{\"containerId\":\""+ fileId +"\"}";
3011                logger.debug(result);
3012               
3013               
3014                logger.debug("  {containerId:"+ fileId+"}");
3015                return Response.status(200).entity(result).build();
3016        }
3017       
3018       
3019        /**
3020         * Recibe los archivos enviador a través del formulario, deserializa el contenedor identificado
3021         * con containerId, agrega los archivos al contenedor, serializa de nuevo el contenedor y retorna
3022         * el identificador del contendor.
3023         *
3024         * @param formParams parametros del formulario
3025         * @param containerId identificador del contenedor pasado en la URL
3026         * 
3027         * @return identificador del contenedor
3028         *
3029         *
3030         * @api {post} /Murachi/0.1/archivos/bdocs/cargas/{containerId} Agrega archivo a contenedor.
3031         * @apiName BDocCargasAgrega
3032         * @apiGroup BDOCS
3033         * @apiVersion 0.1.0
3034         * @apiDescription Agrega el (los) archivo(s) subidos a través del formulario al
3035         * contenedor BDOC identificado por containerId, serializa el contenedor y retorna
3036         * el identificador único del mismo.
3037         *
3038         * @apiSuccess {String} containerId Identificador único del contenedor BDOC.
3039         *
3040         * @apiErrorExample {json} Error-Response:
3041         *     HTTP/1.1 401 Unauthorized
3042         *     {
3043         *       "error": "acceso no autorizado"
3044         *     }
3045         *     
3046         *     HTTP/1.1 500 Internal Server Error
3047         *     {
3048         *       "error": "no se pudo agregar el archivo al contenedor."
3049         *     }
3050         *
3051         */
3052        @POST
3053        @Path("/bdocs/cargas/{containerId}")
3054        @Consumes(MediaType.MULTIPART_FORM_DATA)
3055        @Produces(MediaType.APPLICATION_JSON)
3056        @Authenticator
3057        public Response appendFilesToBDOC(FormDataMultiPart formParams, @PathParam("containerId")  String containerId) throws MurachiException {
3058               
3059                logger.info("recurso /bdocs/cargas/"+containerId);
3060                logger.debug("  appendFilesToBDOC...");
3061               
3062                // cadena con la respuesta
3063                String result = "";
3064               
3065                // ruta del contenedor serializado
3066                String serializedContainerId = "";
3067                                               
3068                if (formParams == null) {
3069                        logger.error("solicitud mal formada.");
3070                        result = "\"error\":\"solicitud mal formada\"";
3071                        return Response.status(400).entity(result).build();
3072                }
3073               
3074                if (containerId == null) {
3075                        logger.error("solicitud mal formada.");
3076                        result = "\"error\":\"solicitud mal formada no se especifico el identificador del contenedor.\"";
3077                        return Response.status(400).entity(result).build();
3078                }
3079               
3080                System.out.println("containerId: "+ containerId);
3081
3082                String containerToOpen = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
3083               
3084                System.out.println("containerToOpen: "+ containerToOpen);
3085
3086                File f = new File(containerToOpen);
3087               
3088                if (!f.exists()) {
3089                        logger.error("el contenedor "+ containerToOpen + " no existe.");
3090                        result = "\"error\":\"el contenedor "+ containerId + " no existe\"";
3091                        return Response.status(404).entity(result).build();     
3092                }
3093               
3094                try {
3095                       
3096                        Security.addProvider(new BouncyCastleProvider());               
3097                       
3098                        Container c;
3099                       
3100                        c = deserialize(containerToOpen);
3101                                               
3102                        int signatureNumber = c.getSignatures().size();                                                 
3103                        logger.debug("  signatureNumber: "+ Integer.toString(signatureNumber));
3104                       
3105                        if (signatureNumber > 0) 
3106                        {
3107                                // el archivo esta firmado y no se puede agregar un archivo adicional                           
3108                                logger.error("el contenedor está firmado y no se puede eliminar el archivo.");
3109                                return Response.status(200).entity("{\"error\": \"el contenedor está firmado y no se puede agregar archivo\"}").type("text/plain").build();
3110                        }
3111                       
3112                       
3113                        Map<String, List<FormDataBodyPart>> fieldsByName = formParams.getFields();
3114                       
3115                        for (List<FormDataBodyPart> fields : fieldsByName.values())
3116                    {
3117                        for (FormDataBodyPart field : fields)
3118                        {
3119                                /*
3120                            InputStream is = field.getEntityAs(InputStream.class);
3121                           
3122                            FormDataContentDisposition file = field.getFormDataContentDisposition();               
3123                            String fileName = file.getFileName();
3124                            String mimeType = field.getMediaType().toString();
3125                            System.out.println("fileName " + fileName);             
3126                            System.out.println("mime " + mimeType);
3127
3128                            addFileToBDOCContainer(is, fileName, mimeType, c);
3129                            */   
3130                           
3131                            InputStream is = field.getEntityAs(InputStream.class);
3132                           
3133                            if (is == null) 
3134                            {
3135                                logger.debug("is: null");
3136                                result = "\"error\":\"archivo pasado al recurso es nulo.\"";
3137                                        return Response.status(500).entity(result).build();
3138                            }             
3139                           
3140                            FormDataContentDisposition file = field.getFormDataContentDisposition();               
3141                            String fileName = file.getFileName();
3142                            logger.debug("fileName: " + fileName);                 
3143                           
3144                            if (fileName == null)
3145                            {
3146                                logger.debug("fileName: null");
3147                                result = "\"error\":\"nombre de archivo pasado al recurso es nulo. Debe especificar un nombre de archivo.\"";
3148                                        return Response.status(500).entity(result).build();
3149                            }               
3150                           
3151                            String mimeType = field.getMediaType().toString();                             
3152                            logger.debug("mimeType: " + mimeType);
3153                           
3154                            if (mimeType == null)
3155                            {
3156                                logger.debug("mimeType: null");
3157                                result = "\"error\":\"tipo mime del archivo pasado al recurso es nulo.\"";
3158                                        return Response.status(500).entity(result).build();
3159                            }
3160                                                           
3161                            try
3162                            {
3163                                addFileToBDOCContainer(is, fileName, mimeType, c);
3164                            }
3165                            catch(Exception e) 
3166                            {
3167                                logger.debug("excepcion: " + e.getMessage());                   
3168                                        result = "\"error\":\"no se pudo insertar el archivo al contenedor.\"";
3169                                        return Response.status(500).entity(result).build();
3170                            }
3171                        }
3172                    }
3173                        // se debe serializar no guardar
3174                                       
3175                        //String[] array = containerId.split("\\.bin");
3176                       
3177                        // establecer el nombre del archivo a serializar
3178                        serializedContainerId = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized";
3179                       
3180                        serialize(c, serializedContainerId);
3181                        logger.debug("  contenedor " + containerToOpen + " serializado.");
3182                       
3183                       
3184                } catch (ClassNotFoundException e) {
3185                        logger.error("error ClassNotFoundException");
3186                        e.printStackTrace();
3187               
3188                        result = "\"error\":\"no se pudo pudo agregar el archivo al contenedor\"";
3189                        e.printStackTrace();
3190                        return Response.status(500).entity(result).build();
3191                       
3192                } catch (IOException e) {
3193                        logger.error("error en la serializacion del contenedor");
3194                        e.printStackTrace();
3195                       
3196                        result = "\"error\":\"no se pudo agregar el archivo al contenedor\"";
3197                        return Response.status(500).entity(result).build();
3198                }
3199
3200                logger.debug("  archivo(s) agregado correctamente a" + containerToOpen);
3201               
3202                result = "{\"containerId\":\""+ containerId +"\"}";             
3203                               
3204                return Response.status(200).entity(result).build();
3205        }
3206               
3207       
3208        /**
3209         * Retorna el numero de dataFile que se encuentran en un contenedor.
3210         *
3211         * @param containerId
3212         * @return numero de archivos almacenados en el contenedor
3213         *
3214         * @api {get} /Murachi/0.1/archivos/bdocs/archivos/{containerId} Número de archivos de contenedor.
3215         * @apiName BDocNumeroDeArchivos
3216         * @apiGroup BDOCS
3217         * @apiVersion 0.1.0
3218         *
3219         * @apiParam {String} containerId identificador únicp del contenedor BDOC que se encuentra en el servidor.
3220         *
3221         * @apiDescription Retorna el número de archivos que se encuentran dentro del contendor BDOC.
3222         *
3223         * @apiSuccess {String} dataFileNumber Número de archivos que se encuentran en el contendor BDOC.
3224         *
3225         * @apiExample Example usage:
3226         *
3227         * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/archivos/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee -k -H "Authorization: Basic YWRtaW46YWRtaW4="
3228         *
3229         *
3230         * @apiErrorExample {json} Error-Response:
3231         *     HTTP/1.1 401 Unauthorized
3232         *     {
3233         *       "error": "acceso no autorizado"
3234         *     }
3235         *     
3236         *     HTTP/1.1 404 Not Found
3237         *     {
3238         *       "error": "el contenedor con identificador containerId no existe ."
3239         *     }
3240         *
3241         *     HTTP/1.1 500 Internal Server Error
3242         *     {
3243         *       "error": "error interno al leer el contenedor."
3244         *     }
3245         *     
3246         *     HTTP/1.1 500 Internal Server Error
3247         *     {
3248         *       "error": "no se pudo leer el contenedor."
3249         *     }
3250         *
3251         */
3252        @GET
3253        @Path("/bdocs/archivos/{containerId}")
3254        @Produces(MediaType.APPLICATION_JSON)
3255        @Authenticator
3256        public Response getDataFileNumber(@PathParam("containerId")  String containerId) {
3257                logger.info("recurso /bdocs/archivos/"+containerId);
3258                                                               
3259                String fullPathBdocFile = "";
3260               
3261                fullPathBdocFile = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
3262                logger.debug("  contenedor a deserializar: " +fullPathBdocFile);
3263
3264                JSONObject json = new JSONObject();
3265                int dataFileNumber = 0;
3266               
3267                Response response = null;
3268                               
3269                // Retrieve the file
3270            File file = new File(fullPathBdocFile);
3271            if (file.exists()) {
3272                               
3273                Security.addProvider(new BouncyCastleProvider());
3274                                               
3275                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
3276                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
3277                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
3278               
3279                        Container c;
3280                       
3281                        try {
3282                                c = deserialize(fullPathBdocFile);
3283                                       
3284                                dataFileNumber = c.getDataFiles().size();
3285                                logger.debug("  dataFileNumber: "+ Integer.toString(dataFileNumber));
3286                                json.put("dataFileNumber", Integer.toString(dataFileNumber));
3287                               
3288                                response = Response.status(200).entity(json.toString()).build();
3289                                       
3290                        } catch (ClassNotFoundException e) {
3291                       
3292                                e.printStackTrace();
3293                               
3294                                json.put("error", "error interno al leer el contenedor");                               
3295                                response = Response.status(500).entity(json.toString()).build();
3296
3297                        } catch (IOException e) {
3298                       
3299                                e.printStackTrace();
3300                                json.put("error", "no se pudo leer el contenedor");                             
3301                                response = Response.status(500).entity(json.toString()).build();
3302                        }
3303            } else {
3304                logger.error("El contenedor con id: "+containerId+ " no existe.");
3305                json.put("error", "El contenedor con id: "+containerId+ " no existe.");
3306                response = Response.status(404).entity(json.toString()).build();
3307            }
3308                return response;
3309        }
3310       
3311       
3312        /**
3313         * Descarga un archivo que se encuentra dentro de un contenedor BDOC.
3314         *
3315         * @param fileId identificador del contenedor BDOC que se encuentra en el servidor
3316         * @param dataFileId identificador del archivo que se desea descargar. Los archivos que
3317         * se encuentran dentro de un contenedor se comienzan a identificar con cero (0).
3318         *
3319         * @return archivo a descagar
3320         *
3321         * @api {get} /Murachi/0.1/archivos/bdocs/archivos/{containerId}/{dataFileId} Descarga un archivo del contenedor.
3322         * @apiDescription Descarga un archivo existente dentro del contenedor BDOC. Un contenedor BDOC puede tener uno
3323         * o varios archivos. Los identificadores de archivos dentro de un contenedor BDOC se comienzan e enumerar con
3324         * cero (0).
3325         *
3326         * @apiName BDocsDescargaArchivo
3327         * @apiGroup BDOCS
3328         * @apiVersion 0.1.0
3329         *
3330         * @apiParam {String} containerId identificador del contenedor BDOC que se encuentra en el servidor
3331         * @apiParam {Number} dataFileId identificador del archivo que se desea descargar. Los archivos que
3332         * se encuentran dentro de un contenedor se comienzan a identificar con cero (0).
3333         *       
3334         *
3335         * @apiExample Example usage:
3336     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/archivos/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee/0 -H "Authorization: Basic YWRtaW46YWRtaW4="
3337         *       
3338         *
3339         * @apiErrorExample {json} Error-Response:
3340         *     HTTP/1.1 401 Unauthorized
3341         *     {
3342         *       "error": "acceso no autorizado"
3343         *     }
3344     *
3345         *     HTTP/1.1 404 Not Found
3346         *     {
3347         *       "fileExist": false
3348         *     }
3349         *     HTTP/1.1 404 Not Found
3350         *     {
3351         *       "error": "el dataFileId solicitado no existe."
3352         *     }     
3353         *     HTTP/1.1 500 Internal server Error
3354         *     {
3355         *       "error": "no se pudo leer el contenido del contenedor."
3356         *     }
3357         *     
3358         */
3359        @GET
3360        @Path("/bdocs/archivos/{containerId}/{dataFileId}")
3361        @Produces(MediaType.APPLICATION_OCTET_STREAM)
3362        @Authenticator
3363        public Response downloadDataFileFromBDOC(@PathParam("containerId")  String containerId, @PathParam("dataFileId")  int dataFileId) {
3364                logger.info("recurso /bdocs/archivos/"+containerId+"/"+Integer.toString(dataFileId));
3365               
3366                logger.debug("dataFileId: " + Integer.toString(dataFileId));
3367                               
3368                String fullPathBdocFile = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin"; 
3369               
3370                Response response;
3371               
3372                // Retrieve the file
3373            File file = new File(fullPathBdocFile);
3374            if (file.exists()) {
3375                               
3376                Security.addProvider(new BouncyCastleProvider());
3377                        Container container = null;
3378                       
3379                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
3380                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
3381                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
3382               
3383                        try {
3384                                container = deserialize(fullPathBdocFile);
3385                                logger.debug("  contenedor " + fullPathBdocFile + " deserializado");
3386                        } catch (ClassNotFoundException e) {
3387
3388                                response = Response.status(500).entity("{\"error\": \"no se pudo leer el contenido del contenedor\"}").type("text/plain").build();
3389                                logger.error("no se pudo deserializar el contenedor para leer su contenido");
3390                        }
3391                        catch (IOException e) {
3392                                response = Response.status(500).entity("{\"error\": \"no se pudo leer el contenido del contenedor\"}").type("text/plain").build();
3393                                logger.error("no se pudo deserializar el contenedor para leer su contenido");
3394                        }
3395                                               
3396                        int dfSize = container.getDataFiles().size();
3397                       
3398                        if (dataFileId > dfSize-1)
3399                        {
3400                                // no existe el dataFile con el id pasado como argumento
3401                                response = Response.status(404).entity("{\"error\": \"el dataFileId solicitado no existe\"}").type("text/plain").build();
3402                                logger.error("el dataFileId solicitado: "+Integer.toString(dataFileId)+ " no existe."); 
3403                        }
3404                        else
3405                        {
3406                                // el dataFile es valido
3407                                DataFile df = container.getDataFile(dataFileId);
3408                                logger.debug("  obtenido DataFile: "+Integer.toString(dataFileId));
3409                               
3410                                String name = df.getName();
3411                                String dfSaved = SERVER_UPLOAD_LOCATION_FOLDER + name; 
3412
3413                                df.saveAs(dfSaved);
3414                                logger.debug("  guardado DataFile: "+dfSaved);
3415                               
3416                                File fileToDownload = new File(dfSaved);
3417                               
3418                                ResponseBuilder builder = Response.ok(fileToDownload);
3419                        builder.header("Content-Disposition", "attachment; filename=" + fileToDownload.getName());
3420                        response = builder.build();
3421                               
3422                        }
3423                                       
3424            } else {
3425                logger.error("El archivo con id: "+containerId+ " no existe.");
3426                response = Response.status(404).entity("{\"fileExist\": false}").type("text/plain").build();
3427            }
3428               
3429                return response;
3430        }
3431       
3432       
3433        /**
3434         * Elimina un archivo DataFile de un contendor existente.
3435         *
3436         * @param containerId identificador del contenedor para eliminar su dataFile.
3437         * @return verificación de eliminación
3438         *
3439         * @api {get} /Murachi/0.1/archivos/bdocs/archivos/papelera/{containerId}/{dataFileId} Elimina un archivo del contenedor.
3440         * @apiDescription Elimina un archivo existente dentro del contenedor BDOC. Un contenedor BDOC puede tener uno
3441         * o varios archivos. Los identificadores de archivos dentro de un contenedor BDOC se comienzan e enumerar con
3442         * cero (0). Para poder eliminar un archivo de un contenedor no deben existir firmas.
3443         *
3444         * @apiName BDocsEliminaArchivos
3445         * @apiGroup BDOCS
3446         * @apiVersion 0.1.0
3447         *
3448         * @apiParam {String} containerId identificador del contenedor BDOC que se encuentra en el servidor.
3449         * @apiParam {Number} dataFileId identificador del archivo que se desea eliminar. Los archivos que
3450         * se encuentran dentro de un contenedor se comienzan a identificar con cero (0).
3451         *
3452         * @apiSuccess {String} mensaje archivo eliminado correctamente
3453         *
3454         * @apiExample Example usage:
3455     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/archivos/papelera/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee/0 -H "Authorization: Basic YWRtaW46YWRtaW4="
3456         *       
3457         *
3458         * @apiErrorExample {json} Error-Response:
3459         *     HTTP/1.1 401 Unauthorized
3460         *     {
3461         *       "error": "acceso no autorizado"
3462         *     }
3463         *     
3464         *     HTTP/1.1 404 Not Found
3465         *     {
3466         *       "fileExist": false
3467         *     }
3468         *     
3469         *     HTTP/1.1 500 Internal server Error
3470         *     {
3471         *       "error": "no se pudo leer el contenido del contenedor."
3472         *     }
3473         *
3474         */
3475        @GET
3476        @Path("/bdocs/archivos/papelera/{containerId}/{dataFileId}")
3477        @Produces(MediaType.APPLICATION_JSON)
3478        @Authenticator
3479        public Response removeDataFile(@PathParam("containerId")  String containerId, @PathParam("dataFileId") int dataFileId) {
3480                logger.info("recurso /bdocs/archivos/papelera/"+containerId+"/"+Integer.toString(dataFileId));
3481               
3482                logger.debug("dataFileId: " + Integer.toString(dataFileId));
3483               
3484                String fullPathBdocFile = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin"; 
3485               
3486                int signatureNumber = 0;
3487               
3488                Response response = null;
3489               
3490                JSONObject json = new JSONObject();
3491               
3492                // Retrieve the file
3493            File file = new File(fullPathBdocFile);
3494            if (file.exists()) {
3495                               
3496                Security.addProvider(new BouncyCastleProvider());
3497                        Container container = null;
3498                       
3499                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
3500                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
3501                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
3502               
3503                        try {
3504                                container = deserialize(fullPathBdocFile);
3505                                logger.debug("  contenedor " + fullPathBdocFile + " deserializado");
3506                        } catch (ClassNotFoundException e) {
3507
3508                                response = Response.status(500).entity("{\"error\": \"no se pudo leer el contenido del contenedor\"}").type("text/plain").build();
3509                                logger.error("no se pudo deserializar el contenedor para leer su contenido");
3510                        }
3511                        catch (IOException e) {
3512                                response = Response.status(500).entity("{\"error\": \"no se pudo leer el contenido del contenedor\"}").type("text/plain").build();
3513                                logger.error("no se pudo deserializar el contenedor para leer su contenido");
3514                        }
3515                               
3516                        // contenedor deserializado, ahora verficar que no este firmado
3517                        signatureNumber = container.getSignatures().size();                                                     
3518                        logger.debug("  signatureNumber: "+ Integer.toString(signatureNumber));
3519                       
3520                        if (signatureNumber > 0) 
3521                        {
3522                                // el archivo esta firmado y no se puede eliminar el dataFile
3523                                response = Response.status(200).entity("{\"error\": \"el contenedor está firmado y no se puede eliminar el archivo\"}").type("text/plain").build();
3524                                logger.error("el contenedor está firmado y no se puede eliminar el archivo.");
3525                        }
3526                        else
3527                        {
3528                                int nDataFile = container.getDataFiles().size();
3529                               
3530                                if (dataFileId >= nDataFile)
3531                                {
3532                                        // el dataFileId no es valido
3533                                        response = Response.status(200).entity("{\"error\": \"el identificador del archivo no es valido\"}").type("text/plain").build();
3534                                        logger.error("el identificador del archivo no es valido.");
3535                                }
3536                                else
3537                                {                               
3538                                        // el dataFile es valido
3539                                        DataFile df = container.getDataFile(dataFileId);
3540                                        logger.debug("  obtenido DataFile: "+Integer.toString(dataFileId) + " fileName: "+ df.getName());
3541                                       
3542                                        container.removeDataFile(df.getName());
3543                                        logger.debug("  eliminado DataFile: "+Integer.toString(dataFileId) + " fileName: "+ df.getName());
3544                                       
3545                                       
3546                                        // serializar el contenedor de nuevo
3547                                        try {
3548                                                serialize(container, SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
3549                                                logger.debug("  contenedor:" + fullPathBdocFile + " serializado.");
3550                                               
3551                                                json.put("mensaje", "archivo eliminado correctamente");                         
3552                                                response = Response.status(200).entity(json.toString()).build();
3553                                               
3554                                        } catch (IOException e) {
3555                                                logger.error("error en la serializacion del contenedor: " + fullPathBdocFile);
3556                                                response = Response.status(500).entity("{\"error\": \"no se serializar el contenedor\"}").type("text/plain").build();
3557                                        }                                       
3558                                }
3559                        }
3560            } else {
3561                logger.error("El archivo con id: "+containerId+ " no existe.");
3562                response = Response.status(404).entity("{\"fileExist\": false}").type("text/plain").build();
3563            }
3564               
3565                return response;
3566                               
3567        }
3568       
3569       
3570       
3571        /**
3572         * Retorna lista de los dataFile que se encuentran en un contenedor.
3573         *
3574         * @param containerId identificador del contenedor.
3575         * @return lista de los dataFile que se encuentran en un contenedor.
3576         *
3577         * @api {get} /Murachi/0.1/archivos/bdocs/archivos/lista/{containerId} Lista de archivos del contenedor.
3578         * @apiDescription Retorna una lista de los archivos que se encuentran dentro del contenedor BDOC.
3579         *
3580         * @apiName BDocsListaArchivos
3581         * @apiGroup BDOCS
3582         * @apiVersion 0.1.0
3583         *
3584         * @apiParam {String} containerId identificador del contenedor BDOC que se encuentra en el servidor.
3585         *
3586         * @apiSuccess {String} dataFiles lista de archivos que se encuentran en el contenedor.
3587         *
3588         * @apiExample Example usage:
3589     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/archivos/lista/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee -H "Authorization: Basic YWRtaW46YWRtaW4="
3590         *       
3591         *
3592         * @apiErrorExample {json} Error-Response:
3593         *     HTTP/1.1 401 Unauthorized
3594         *     {
3595         *       "error": "acceso no autorizado"
3596         *     }
3597         *     
3598         *     HTTP/1.1 404 Not Found
3599         *     {
3600         *       "error": "El contenedor con identificador containerId no existe."
3601         *     }
3602         *     
3603         *     HTTP/1.1 500 Internal server Error
3604         *     {
3605         *       "error": "no se pudo leer el contenido del contenedor."
3606         *     }
3607     *     
3608     *     HTTP/1.1 500 Internal server Error
3609         *     {
3610         *       "error": "El contenedor tiene un número menor que cero de archivos."
3611         *     }
3612         * 
3613         */
3614        @GET
3615        @Path("/bdocs/archivos/lista/{containerId}")
3616        @Produces(MediaType.APPLICATION_JSON)
3617        @Authenticator
3618        public Response getDataFileList(@PathParam("containerId")  String containerId) {
3619       
3620               
3621                logger.info("recurso /bdocs/archivos/lista/"+containerId);
3622               
3623                String fullPathBdocFile = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
3624                logger.debug(fullPathBdocFile);
3625               
3626                JSONObject jsonDataFile = new JSONObject();
3627                int dataFileNumber = 0;
3628               
3629                Response response = null;
3630                               
3631                // Retrieve the file
3632            File file = new File(fullPathBdocFile);
3633            if (file.exists()) {
3634                               
3635                Security.addProvider(new BouncyCastleProvider());
3636                                               
3637                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
3638                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
3639                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
3640               
3641                        Container c = null;
3642                        String dataFileName = "";
3643                        Long dataFileSize = (long) 0;
3644                                       
3645                        try {
3646                                c = deserialize(fullPathBdocFile);
3647                                logger.debug("contenedor deserializado: " + fullPathBdocFile);
3648                                       
3649                        } catch (ClassNotFoundException e) {
3650                               
3651                                jsonDataFile.put("error", "error interno al leer el contenedor");                               
3652                                response = Response.status(500).entity(jsonDataFile.toString()).build();
3653                                return response;
3654
3655                        } catch (IOException e) {
3656                                jsonDataFile.put("error", "no se pudo leer el contenedor");                             
3657                                response = Response.status(500).entity(jsonDataFile.toString()).build();
3658                                return response;
3659                        }
3660                               
3661                        dataFileNumber = c.getDataFiles().size();
3662                        logger.debug("dataFileNumber: " + Integer.toString(dataFileNumber));
3663                       
3664                        if (dataFileNumber > 0)
3665                        {
3666                                for (int i=0; i<dataFileNumber; i++)
3667                                {
3668                                        // el dataFile es valido
3669                                        DataFile df = c.getDataFile(i);
3670                                        dataFileName = df.getName();
3671                                        dataFileSize = df.getFileSize();
3672                                        logger.debug("obtenido DataFile: "+Integer.toString(i));
3673                                        logger.debug("DataFile name: "+ dataFileName);
3674                                        logger.debug("DataFile size: "+ Long.toString(dataFileSize));
3675                                }
3676                                jsonDataFile.put("dataFiles", getJSONFromBDOCDataFiles(c.getDataFiles()));
3677                                response = Response.status(200).entity(jsonDataFile.toString()).build();
3678                        }
3679                        else if (dataFileNumber == 0)
3680                        {
3681                                logger.debug("dataFileNumber: "+ Integer.toString(dataFileNumber));
3682                                jsonDataFile.put("dataFileNumber", Integer.toString(dataFileNumber));
3683                                response = Response.status(200).entity(jsonDataFile.toString()).build();
3684                        }
3685                        else
3686                        {
3687                                logger.error("El contenedor con id: "+containerId+ " tiene un número menor que cero de dataFiles.");
3688                        jsonDataFile.put("error", "El contenedor tiene un número menor que cero de archivos");
3689                        response = Response.status(500).entity(jsonDataFile.toString()).build();
3690                        }
3691                       
3692                                                                                                               
3693            } else {
3694                logger.error("El contenedor con id: "+containerId+ " no existe.");
3695                jsonDataFile.put("error", "El contenedor con identificador "+containerId+ " no existe.");
3696                response = Response.status(404).entity(jsonDataFile.toString()).build();
3697            }
3698                return response;
3699        }
3700
3701               
3702       
3703        /**
3704         * Retorna el numero de firmas que tiene en un contenedor.
3705         *
3706         * @param containerId identificador del contenedor BDOC.
3707         * @return numero de firmas del contenedor.
3708         *
3709         * @api {get} /Murachi/0.1/archivos/bdocs/firmas/{containerId} Número de firmas de un contenedor.
3710         * @apiName BDocNumeroFirmas
3711         * @apiGroup BDOCS
3712         * @apiVersion 0.1.0
3713         *
3714         * @apiParam {String} containerId identificador único del contenedor BDOC que se encuentra en el servidor.
3715         *
3716         * @apiDescription Retorna el número de firmas del contendor BDOC.
3717         *
3718         * @apiExample Example usage:
3719     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/firmas/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee -H "Authorization: Basic YWRtaW46YWRtaW4="
3720         *
3721         * @apiSuccess {String} signatureNumber Número de firmas del contendor BDOC.
3722         *
3723         * @apiErrorExample {json} Error-Response:
3724         *     HTTP/1.1 401 Unauthorized
3725         *     {
3726         *       "error": "acceso no autorizado"
3727         *     }
3728         *     
3729         *     HTTP/1.1 404 Not Found
3730         *     {
3731         *       "error": "el contenedor con identificador containerId no existe ."
3732         *     }
3733         *     
3734         *     HTTP/1.1 500 Internal Server Error
3735         *     {
3736         *       "error": "error interno al leer el contenedor."
3737         *     }
3738         
3739         */
3740        @GET
3741        @Path("/bdocs/firmas/{containerId}")
3742        @Produces(MediaType.APPLICATION_JSON)
3743        @Authenticator
3744        public Response getSignatureNumber(@PathParam("containerId")  String containerId) {
3745                logger.info("/bdocs/firmas/"+containerId);
3746                                                               
3747                String fullPathBdocFile = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
3748                logger.debug(fullPathBdocFile);
3749               
3750               
3751                JSONObject json = new JSONObject();
3752                int signatureNumber = 0;
3753               
3754                Response response;
3755                               
3756                // Retrieve the file
3757            File file = new File(fullPathBdocFile);
3758            if (file.exists()) {
3759                               
3760                Security.addProvider(new BouncyCastleProvider());
3761                                               
3762                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
3763                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
3764                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
3765               
3766                        Container c;
3767                       
3768                        try {
3769                                c = deserialize(fullPathBdocFile);
3770                               
3771                                signatureNumber = c.getSignatures().size();                             
3772                               
3773                                logger.debug("signatureNumber: "+ Integer.toString(signatureNumber));
3774                                json.put("signatureNumber", Integer.toString(signatureNumber));
3775                               
3776                                response = Response.status(200).entity(json.toString()).build();
3777                               
3778                        } catch (ClassNotFoundException e) {
3779                                                       
3780                                json.put("error", "error interno al leer el contenedor");                               
3781                                response = Response.status(500).entity(json.toString()).build();
3782
3783                        } catch (IOException e) {
3784                               
3785                                json.put("error", "no se pudo leer el contenedor");                             
3786                                response = Response.status(500).entity(json.toString()).build();
3787                        }                                                                                       
3788            } else {
3789                logger.error("El contenedor con id: "+containerId+ " no existe.");
3790                json.put("error", "El contenedor con id: "+containerId+ " no existe.");
3791                response = Response.status(404).entity(json.toString()).build();
3792            }
3793                return response;               
3794        }
3795       
3796       
3797        /**
3798         * Elimina una firma de un contendor firmado
3799         *
3800         * @param containerId identificador del contenedor para eliminar la firma
3801         * @param signatureId identificador de la firma a eliminar
3802         *
3803         * @return identificador del contenedor.
3804         *
3805         * * @api {get} /Murachi/0.1/archivos/bdocs/firmas/papelera/{containerId}/{signatureId} Elimina una firma de un contenedor.
3806         * @apiName BDocEliminaFirmas
3807         * @apiGroup BDOCS
3808         * @apiVersion 0.1.0
3809         *
3810         * @apiParam {String} containerId identificador único del contenedor BDOC que se encuentra en el servidor.
3811         * @apiParam {Number} signatureId identificador de firma a eliminar.
3812         *
3813         * @apiDescription Elimina una firma del contendor BDOC.
3814     *
3815         * @apiExample Example usage:
3816     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/firmas/papelera/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee -H "Authorization: Basic YWRtaW46YWRtaW4="
3817     *
3818         * @apiSuccess {String} mensaje firma eliminada correctamente
3819         *
3820         * @apiErrorExample {json} Error-Response:
3821         *     HTTP/1.1 401 Unauthorized
3822         *     {
3823         *       "error": "acceso no autorizado"
3824         *     }
3825         *     
3826         *     HTTP/1.1 404 Not Found
3827         *     {
3828         *       "error": "el contenedor con identificador containerId no existe ."
3829         *     }
3830         *     
3831         *     HTTP/1.1 500 Internal Server Error
3832         *     {
3833         *       "error": "no se pudo leer el contenido del contenedor."
3834         *     }
3835         *
3836         */
3837        @GET
3838        @Path("/bdocs/firmas/papelera/{containerId}/{signatureId}")
3839        @Produces(MediaType.APPLICATION_JSON)
3840        @Authenticator
3841        public Response removeSignature(@PathParam("containerId")  String containerId, @PathParam("signatureId") int signatureId) {
3842                logger.info("recurso /bdocs/firmas/papelera/"+containerId+"/"+Integer.toString(signatureId));
3843               
3844                logger.debug("dataFileId: " + Integer.toString(signatureId));
3845               
3846                String fullPathBdocFile = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
3847                logger.debug(fullPathBdocFile);
3848               
3849               
3850                JSONObject json = new JSONObject();
3851                int signatureNumber = 0;
3852               
3853                Response response = null;
3854                               
3855                // Retrieve the file
3856            File file = new File(fullPathBdocFile);
3857            if (file.exists()) {
3858                               
3859                Security.addProvider(new BouncyCastleProvider());
3860                                               
3861                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
3862                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
3863                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
3864               
3865                        Container container = null;
3866                       
3867                        try {
3868                                container = deserialize(fullPathBdocFile);
3869                                logger.debug("  contenedor " + fullPathBdocFile + " deserializado");
3870                        } catch (ClassNotFoundException e) {
3871
3872                                response = Response.status(500).entity("{\"error\": \"no se pudo leer el contenido del contenedor\"}").type("text/plain").build();
3873                                logger.error("no se pudo deserializar el contenedor para leer su contenido");
3874                        }
3875                        catch (IOException e) {
3876                                response = Response.status(500).entity("{\"error\": \"no se pudo leer el contenido del contenedor\"}").type("text/plain").build();
3877                                logger.error("no se pudo deserializar el contenedor para leer su contenido");
3878                        }
3879                               
3880                        // contenedor deserializado, ahora verficar que este firmado
3881                        signatureNumber = container.getSignatures().size();                                                     
3882                        logger.debug("  signatureNumber: "+ Integer.toString(signatureNumber));
3883                       
3884                        if (signatureNumber < 1) 
3885                        {
3886                                // el archivo no esta firmado y no se puede eliminar la firma
3887                                response = Response.status(200).entity("{\"error\": \"el contenedor no está firmado\"}").type("text/plain").build();
3888                                logger.error("el contenedor no está firmado.");
3889                        }
3890                        else
3891                        {                               
3892                                if (signatureId >= signatureNumber)
3893                                {
3894                                        // el signatureId no es valido
3895                                        response = Response.status(200).entity("{\"error\": \"el identificador de la firma a eliminar no es valido\"}").type("text/plain").build();
3896                                        logger.error("el identificador de la firma a eliminar no es valido.");
3897                                }
3898                                else
3899                                {
3900                                        // eliminar la firma
3901                                        container.removeSignature(signatureId);
3902                                        logger.debug("  eliminada signature: "+Integer.toString(signatureId));
3903                               
3904                                        // serializar el contenedor de nuevo
3905                                        try {
3906                                                serialize(container, SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
3907                                                logger.debug("  serializado contenedor:" + fullPathBdocFile + " serializado.");
3908                                       
3909                                                json.put("mensaje", "firma eliminada correctamente");                           
3910                                                response = Response.status(200).entity(json.toString()).build();
3911                                       
3912                                        } catch (IOException e) {
3913                                                logger.error("error en la serializacion del contenedor: " + fullPathBdocFile);
3914                                                response = Response.status(500).entity("{\"error\": \"no se serializar el contenedor\"}").type("text/plain").build();
3915                                        }                                       
3916                                }                               
3917                        }                       
3918                } else {
3919                logger.error("El contenedor con id: "+containerId+ " no existe.");
3920                json.put("error", "El contenedor con id: "+containerId+ " no existe.");
3921                response = Response.status(404).entity(json.toString()).build();
3922            }
3923                return response;
3924                       
3925        }
3926
3927       
3928        /**
3929         * Retorna una lista con información de las firmas que tiene en un contenedor.
3930         *
3931         * @param containerId identificador del contenedor BDOC.
3932         * @return lista con información de las firmas que tiene en un contenedor.
3933         *
3934         * @api {get} /Murachi/0.1/archivos/bdocs/firmas/lista/{containerId} Lista de firmas de un contenedor.
3935         * @apiName BDocListaFirmas
3936         * @apiGroup BDOCS
3937         * @apiVersion 0.1.0
3938         *
3939         * @apiParam {String} containerId identificador único del contenedor BDOC que se encuentra en el servidor.
3940         *
3941         * @apiDescription Retorna una lista con la información de las firmas del contendor BDOC.
3942         *
3943         * @apiSuccess {Number} numberOfSignatures Número de firmas existentes en el archivo.
3944         * @apiSuccess {Object[]} signatures Lista de firmas del contenedor BDOC
3945         * @apiSuccess {String} signatures.signaturePostalCode Código postal del lugar donde se realiza la firma.
3946         * @apiSuccess {String} signatures.signerCertificateSerial Serial del certificado del firmante.
3947         * @apiSuccess {String} signatures.signatureState Estado del lugar donde se realiza la firma.
3948         * @apiSuccess {String} signatures.signatureProfile Perfil de la firma.
3949         * @apiSuccess {String} signatures.signatureMethod Algoritmo de firma utilizado.
3950         * @apiSuccess {String} signatures.signatureId identificador de la firma.
3951         * @apiSuccess {String} signatures.signatureSigningTime Hora y fecha en que se realiza la firma.
3952         * @apiSuccess {Boolean} signatures.signerCertificateIsValid El certificado firmante es válido.
3953         * @apiSuccess {String} signatures.signerCertificateIssuer Emisor del certificado firmante.
3954         * @apiSuccess {String} signatures.signatureCity Ciudad donde se realiza la firma.
3955         * @apiSuccess {String} signatures.signatureValidationException Exepciones de la validación de la firma.
3956         * @apiSuccess {String} signatures.isValid Firma electrónica válida.
3957         * @apiSuccess {String} signatures.signerCertificateIssuer Emisor del certificado firmante.
3958         * @apiSuccess {String} signatures.signatureCountry País donde se realiza la firma.
3959         *
3960     * @apiExample Example usage:
3961     * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/firmas/lista/f011ff87-f0d0-4a5e-a0b9-a64eb70661ee -H "Authorization: Basic YWRtaW46YWRtaW4="
3962         *
3963         * @apiSuccess {Boolean}   containerValidation: Especifica si el contenedor posee una estructura válida. 
3964         *
3965         * @apiErrorExample {json} Error-Response:
3966         *     HTTP/1.1 401 Unauthorized
3967         *     {
3968         *       "error": "acceso no autorizado"
3969         *     }
3970         *     
3971         *     HTTP/1.1 404 Not Found
3972         *     {
3973         *       "error": "el contenedor con identificador containerId no existe ."
3974         *     }
3975         *     
3976         *     HTTP/1.1 500 Internal Server Error
3977         *     {
3978         *       "error": "error interno al leer el contenedor."
3979         *     }
3980         *     
3981         *     HTTP/1.1 500 Internal Server Error
3982         *     {
3983         *       "error": "El contenedor tiene un número menor que cero de firmas"
3984         *     }
3985         *     
3986         */
3987        @GET
3988        @Path("/bdocs/firmas/lista/{containerId}")
3989        @Produces(MediaType.APPLICATION_JSON)
3990        @Authenticator
3991        public Response getSignaturesList(@PathParam("containerId")  String containerId) {
3992                logger.info("/bdocs/firmas/lista/"+containerId);
3993                                                               
3994                String fullPathBdocFile = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
3995                logger.debug(fullPathBdocFile);
3996               
3997               
3998                JSONObject jsonSignatures = new JSONObject();
3999                int signatureNumber = 0;
4000               
4001                Response response;
4002                               
4003                // Retrieve the file
4004            File file = new File(fullPathBdocFile);
4005            if (file.exists()) {
4006                               
4007                Security.addProvider(new BouncyCastleProvider());
4008                                               
4009                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
4010                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
4011                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
4012               
4013                        Container c;
4014                       
4015                        try {
4016                                c = deserialize(fullPathBdocFile);
4017                               
4018                                signatureNumber = c.getSignatures().size();                             
4019                               
4020                                logger.debug("signatureNumber: "+ Integer.toString(signatureNumber));
4021                               
4022                                if (signatureNumber > 0) {                                     
4023                                        jsonSignatures = getSignaturesInformation(c);                                   
4024                                }
4025                                else if(signatureNumber == 0) 
4026                                {
4027                                        logger.debug("numberOfSignatures: "+ Integer.toString(signatureNumber));
4028                                        jsonSignatures.put("numberOfSignatures", Integer.toString(signatureNumber));
4029                                        response = Response.status(200).entity(jsonSignatures.toString()).build();
4030                                }
4031                                else
4032                                {
4033                                        logger.error("El contenedor con id: "+containerId+ " tiene un número menor que cero de firmas.");
4034                                jsonSignatures.put("error", "El contenedor tiene un número menor que cero de firmas");
4035                                response = Response.status(500).entity(jsonSignatures.toString()).build();
4036                                }
4037                                                       
4038                                response = Response.status(200).entity(jsonSignatures.toString()).build();
4039                               
4040                        } catch (ClassNotFoundException e) {
4041                                                       
4042                                jsonSignatures.put("error", "error interno al leer el contenedor");                             
4043                                response = Response.status(500).entity(jsonSignatures.toString()).build();
4044
4045                        } catch (IOException e) {
4046                               
4047                                jsonSignatures.put("error", "no se pudo leer el contenedor");                           
4048                                response = Response.status(500).entity(jsonSignatures.toString()).build();
4049                        }                                                                                       
4050            } else {
4051                logger.error("El contenedor con id: "+containerId+ " no existe.");
4052                jsonSignatures.put("error", "El contenedor con id: "+containerId+ " no existe.");
4053                response = Response.status(404).entity(jsonSignatures.toString()).build();
4054            }
4055                return response;               
4056        }
4057       
4058       
4059       
4060        /**
4061         * Ejecuta la prefirma de un contenedor BDOC calculando el hash y enviandolo al cliente para que lo firme.
4062         *
4063         * @param presignPar Parametros para preparar la firma.
4064         * @return hash del archivo a firmar del lado del cliente.
4065         * @throws MurachiException
4066         *
4067         * @api {post} /Murachi/0.1/archivos/bdocs/firmas/pre Prepara la firma de un contenedor BDOC.
4068         * @apiName BDocsFirmasPre
4069         * @apiGroup BDOCS
4070         * @apiVersion 0.1.0
4071         * @apiDescription Prepara la firma de un contenedor BDOC existente en el servidor.
4072         * Se debe pasar un JSON con la siguiente estructura:
4073         *
4074         * {"fileId":"file_id", "certificate":"hex_cert_value",
4075         * "city":"ciudad", "state":"estado", "postalCode":"codigoPostal",
4076         * "country":"pais", "role":"rol"}
4077         * 
4078         *  fileId: corresponde al identificador del contenedor que se encuentra en el servidor y se desea firmar.
4079         * 
4080         *  certificate: corresponde al certificado del firmante en formato hexadecimal.
4081         * 
4082         *  city: corresponde a la ciudad en la que se realiza la firma.
4083         * 
4084         *  state: corresponde al estado en el que se reailza la firma.
4085         * 
4086         *  postalCode: corresponde al código postal del lugar donde se realiza la firma.
4087         * 
4088         *  country: corresponde al país donde se realiza la firma.
4089         * 
4090         *  role: corresponde al rol del firmante.
4091         * 
4092         * @apiSuccess {String} hash Reseña o hash del contenedor que se debe cifrar con la clave privada protegida por el
4093         * dispositivo criptográfico.
4094         *
4095         * @apiExample Example usage:
4096         *
4097         * var parameters = JSON.stringify({
4098         *                             "fileId":fileId,
4099         *                             "certificate":cert.hex,
4100         *                             "city":"Merida",
4101     *                             "state":"Merida",
4102         *                             "postalCode":"5101",
4103         *                             "country":"Venezuela",
4104         *                             "role":"Desarrollador"
4105         *                             });
4106         *
4107         * $.ajax({
4108     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/firmas/pre",
4109     *           type: "post",
4110     *           dataType: "json",
4111     *           data: parameters,
4112     *           contentType: "application/json",
4113     *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
4114     *           success: function(data, textStatus, jqXHR){
4115         *                              var json_x = data;
4116     *                              var hash = json_x['hash'];
4117     *                              alert("hash recibido del servidor "+hash);
4118     *           },
4119         *           error: function(jqXHR, textStatus, errorThrown){
4120         *                              //alert('error: ' + textStatus);
4121         *                              //var responseText = jQuery.parseJSON(jqXHR.responseText);
4122         *                              alert('ajax error function: ' + jqXHR.responseText);
4123         *                             
4124         *           }
4125     *  });
4126         *
4127         *
4128         *
4129         * @apiErrorExample {json} Error-Response:
4130         *     HTTP/1.1 401 Unauthorized
4131         *     {
4132         *       "error": "acceso no autorizado"
4133         *     }
4134         *     
4135         *     HTTP/1.1 404 Not Found
4136         *     {
4137         *       "error": "el contenedor con identificador containerId no existe ."
4138         *     }
4139         *     
4140         *     HTTP/1.1 500 Internal Server Error
4141         *     {
4142         *       "hash": "",
4143         *       "error": "Error en el certificado del firmante"
4144         *     }
4145         *
4146         */
4147        @POST
4148        @Path("/bdocs/firmas/pre")
4149        @Consumes(MediaType.APPLICATION_JSON)
4150        @Produces(MediaType.APPLICATION_JSON)
4151        @Authenticator
4152        public Response presignBDOCContainer(PresignParametersBdoc presignPar) throws MurachiException {
4153               
4154                String result = "";
4155               
4156                logger.info("recurso /bdocs/firmas/pre");
4157               
4158                PresignHash presignHash = new PresignHash();
4159                logger.debug("presignPar: " + presignPar);
4160               
4161                if (presignPar == null) {
4162                // registrar error de firma en estadisticas
4163                        registerASignatureError(1);
4164                       
4165                        logger.error("solicitud mal formada.");
4166                        result = "\"error\":\"solicitud mal formada\"";
4167                        return Response.status(400).entity(result).build();     
4168                }
4169                               
4170                // obtener el id del archivo a firmar
4171                String containerId = presignPar.getFileId();           
4172                if (containerId == null) {
4173                // registrar error de firma en estadisticas
4174                        registerASignatureError(1);
4175                       
4176                        logger.debug("containerId == null");
4177                        logger.error("solicitud mal formada: no esta especificado el identificador del contenedor.");
4178                        result = "\"error\":\"solicitud mal formada: : no esta especificado el identificador del contenedor\"";
4179                        return Response.status(400).entity(result).build();
4180                }
4181                logger.debug("  containerId: " + containerId);
4182                               
4183                // cadena con el certificado
4184                String certHex = presignPar.getCertificate();           
4185                if (certHex == null) {
4186                // registrar error de firma en estadisticas
4187                        registerASignatureError(1);
4188                       
4189                        logger.debug("certHex == null");
4190                        logger.error("solicitud mal formada: no esta especificado el certificado firmante en hexadecimal.");
4191                        result = "\"error\":\"solicitud mal formada: : no esta especificado el certificado firmante en hexadecimal\"";
4192                        return Response.status(400).entity(result).build();
4193                }
4194                logger.debug("  certHex: " + certHex);
4195
4196                String city = presignPar.getCity();
4197                if (city == null) {
4198                // registrar error de firma en estadisticas
4199                        registerASignatureError(1);
4200                       
4201                        logger.debug("city == null");
4202                        logger.error("solicitud mal formada: no esta especificada la ciudad donde se realiza la firma.");
4203                        result = "\"error\":\"solicitud mal formada: : no esta especificada la ciudad donde se realiza la firma\"";
4204                        return Response.status(400).entity(result).build();
4205                }               
4206                logger.debug("  city: " + city);
4207               
4208                String state = presignPar.getState();
4209                if (state == null) {
4210                // registrar error de firma en estadisticas
4211                        registerASignatureError(1);
4212                       
4213                        logger.debug("state == null");
4214                        logger.error("solicitud mal formada: no esta especificado el estado donde se realiza la firma.");
4215                        result = "\"error\":\"solicitud mal formada: : no esta especificado el estado donde se realiza la firma\"";
4216                        return Response.status(400).entity(result).build();
4217                }
4218                logger.debug("  state: " + state);
4219               
4220                String postalCode = presignPar.getPostalCode();
4221                if (postalCode == null) {
4222                // registrar error de firma en estadisticas
4223                        registerASignatureError(1);
4224                       
4225                        logger.debug("state == null");
4226                        logger.error("solicitud mal formada: no esta especificado el codigo postal donde se realiza la firma.");
4227                        result = "\"error\":\"solicitud mal formada: : no esta especificado el codigo postal donde se realiza la firma\"";
4228                        return Response.status(400).entity(result).build();
4229                }
4230                logger.debug("  postalCode: " + postalCode);
4231               
4232                String country = presignPar.getCountry();
4233                if (country == null) {
4234                // registrar error de firma en estadisticas
4235                        registerASignatureError(1);
4236                       
4237                        logger.debug("country == null");
4238                        logger.error("solicitud mal formada: no esta especificado el pais donde se realiza la firma.");
4239                        result = "\"error\":\"solicitud mal formada: : no esta especificado el pais donde se realiza la firma\"";
4240                        return Response.status(400).entity(result).build();
4241                }
4242                logger.debug("  country: " + country);
4243               
4244                String role = presignPar.getRole();
4245                if (role == null) {
4246                // registrar error de firma en estadisticas
4247                        registerASignatureError(1);
4248                       
4249                        logger.debug("role == null");
4250                        logger.error("solicitud mal formada: no esta especificado el rol del firmante.");
4251                        result = "\"error\":\"solicitud mal formada: : no esta especificado el el rol del firmante\"";
4252                        return Response.status(400).entity(result).build();
4253                }
4254                logger.debug("  role: " + role);
4255               
4256                //Boolean addSignature = presignPar.getAddSignature();
4257                //logger.debug("        addSignature: " + addSignature.toString());
4258               
4259                CertificateFactory cf;
4260                X509Certificate signerCert;
4261               
4262                //
4263                String hashToSign = "";
4264               
4265                SignedInfo signedInfo;
4266               
4267                String fullPathContainerId = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
4268                System.out.println("archivo a firmar: " + fullPathContainerId);
4269                logger.debug("archivo a firmar: " + fullPathContainerId);
4270               
4271                String sourceFileMimeType = getMimeTypeWithTika(fullPathContainerId);
4272                logger.debug("mimeType del archivo a firmar: " + sourceFileMimeType);
4273               
4274                certHex = presignPar.getCertificate();
4275                System.out.println("certificado en Hex: " + certHex);
4276                logger.debug("certificado firmante en Hex: " + certHex);
4277               
4278                File f = new File(fullPathContainerId);
4279               
4280                if (!f.exists()) {
4281                // registrar error de firma en estadisticas
4282                        registerASignatureError(1);
4283                       
4284                        logger.error("el contenedor "+ fullPathContainerId + " no existe.");
4285                        result = "\"error\":\"el contenedor "+ fullPathContainerId + " no existe\"";
4286                        return Response.status(404).entity(result).build();     
4287                }
4288                               
4289                try
4290                {
4291                        /*
4292                        Security.addProvider(new BouncyCastleProvider());
4293                        Container container = null;
4294               
4295                        Configuration configuration = new Configuration(Configuration.Mode.PROD);
4296               
4297                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
4298               
4299                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
4300
4301                        // deserializar el contenedor
4302                        container = deserialize(fullPathContainerId);
4303                        logger.debug("deserializado el contenedor: " + fullPathContainerId);
4304                       
4305                        SignatureParameters signatureParameters = new SignatureParameters();
4306                        SignatureProductionPlace productionPlace = new SignatureProductionPlace();
4307                        productionPlace.setCity(city);
4308                        productionPlace.setStateOrProvince(state);
4309                        productionPlace.setPostalCode(postalCode);
4310                        productionPlace.setCountry(country);
4311                        signatureParameters.setProductionPlace(productionPlace);
4312                        logger.debug("container setProductionPlace");
4313                       
4314                        signatureParameters.setRoles(asList(role));
4315                        container.setSignatureParameters(signatureParameters);
4316                        container.setSignatureProfile(SignatureProfile.B_BES);
4317                               
4318                        cf = CertificateFactory.getInstance("X.509");
4319               
4320                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
4321               
4322                        signerCert = (X509Certificate) cf.generateCertificate(in);
4323               
4324                        signedInfo = container.prepareSigning(signerCert);
4325               
4326                        hashToSign = byteArrayToHexString(signedInfo.getDigest());
4327               
4328                        System.out.println("presignBdoc - hash: " + hashToSign);
4329                        logger.debug("hash to sign: " + hashToSign);
4330               
4331                       
4332                        //String[] array = containerId.split("\\.bin");
4333                       
4334                        // establecer el nombre del archivo a serializar
4335                        String serializedContainerId = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized";
4336                        logger.debug("serializedContainerId: " + serializedContainerId);
4337               
4338                        // serializar el archivo
4339                        serialize(container, serializedContainerId);
4340                        logger.debug("serializado el contenedor: " + serializedContainerId);
4341                        */
4342                       
4343                       
4344                        Security.addProvider(new BouncyCastleProvider());
4345                        Container container = null;                     
4346               
4347                        Configuration configuration = new Configuration(Configuration.Mode.PROD);               
4348                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
4349                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
4350
4351                       
4352                        // deserializar el contenedor
4353                       
4354                        logger.debug("antes de deserializar el contenedor: " + fullPathContainerId);
4355                       
4356                        //container = deserialize(fullPathContainerId);
4357                        container = deserializer1(fullPathContainerId);
4358                       
4359                        logger.debug("deserializado el contenedor: " + fullPathContainerId);
4360
4361                       
4362                        SignatureParameters signatureParameters = new SignatureParameters();
4363                        SignatureProductionPlace productionPlace = new SignatureProductionPlace();
4364                        productionPlace.setCity(city);
4365                        productionPlace.setStateOrProvince(state);
4366                        productionPlace.setPostalCode(postalCode);
4367                        productionPlace.setCountry(country);
4368                        signatureParameters.setProductionPlace(productionPlace);
4369                        logger.debug("container setProductionPlace");
4370                       
4371                        signatureParameters.setRoles(asList(role));
4372                        container.setSignatureParameters(signatureParameters);
4373                        container.setSignatureProfile(SignatureProfile.B_BES);
4374                               
4375                        cf = CertificateFactory.getInstance("X.509");
4376               
4377                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
4378               
4379                        signerCert = (X509Certificate) cf.generateCertificate(in);
4380               
4381                        signedInfo = container.prepareSigning(signerCert);
4382               
4383                        hashToSign = byteArrayToHexString(signedInfo.getDigest());
4384               
4385                        System.out.println("presignBdoc - hash: " + hashToSign);
4386                        logger.debug("hash to sign: " + hashToSign);
4387               
4388                       
4389                        //String[] array = containerId.split("\\.bin");
4390                       
4391                        // establecer el nombre del archivo a serializar
4392                        String serializedContainerId = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized";
4393                        logger.debug("serializedContainerId: " + serializedContainerId);
4394               
4395                        // serializar el archivo
4396                        serialize(container, serializedContainerId);
4397                        logger.debug("serializado el contenedor: " + serializedContainerId);
4398                       
4399                       
4400                               
4401                } catch(IOException e)
4402                {
4403                // registrar error de firma en estadisticas
4404                        registerASignatureError(1);
4405                       
4406                // registrar error de firma en estadisticas
4407                        registerASignatureError(1);
4408                        presignHash.setError(e.getMessage());
4409                        presignHash.setHash("");
4410                        return Response.status(500).entity(presignHash).build();
4411                } catch(CertificateException e)
4412                {
4413                // registrar error de firma en estadisticas
4414                        registerASignatureError(1);
4415                       
4416                        presignHash.setError(e.getMessage());
4417                        presignHash.setHash("");
4418                        return Response.status(500).entity(presignHash).build();
4419                } catch (ClassNotFoundException e) {
4420                // registrar error de firma en estadisticas
4421                        registerASignatureError(1);
4422                       
4423                        presignHash.setError(e.getMessage());
4424                        presignHash.setHash("");
4425                        return Response.status(500).entity(presignHash).build();
4426                }
4427               
4428                       
4429                       
4430                // creacion del json
4431                JSONObject jsonHash = new JSONObject();
4432                jsonHash.put("hashToSign", hashToSign);
4433
4434                presignHash.setHash(hashToSign);
4435                presignHash.setError("");               
4436               
4437                logger.debug("presignBDOCContainer: "+ presignHash.getHash());
4438                return Response.status(200).entity(presignHash).build();                       
4439        }
4440       
4441       
4442       
4443        /**
4444         * Ejecuta el proceso de completacion de la firma de contenedor BDOC
4445         *
4446         * @param postsignPar Parametros para completar la firma del contenedor BDOC
4447         * @return identificador del contenedor firmado
4448         *
4449         * @throws IOException
4450         * @throws MurachiException
4451         *
4452         * @api {post} /Murachi/0.1/archivos/bdocs/firmas/post Completa la firma de un contenedor BDOC.
4453         * @apiName BdocFirmasPost
4454         * @apiGroup BDOCS
4455         * @apiVersion 0.1.0
4456         * @apiDescription Completa la firma de un contenedor BDOC. Recibe el hash cifrado del cliente y 
4457         * completa la firma del contenedor BDOC.
4458         *
4459         * @apiSuccess {String} signedFileId Identificador único del contenedor firmado en el servidor.
4460         *
4461         * @apiExample Example usage:
4462         *
4463         * $.ajax({
4464     *           url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/bdocs/firmas/post",
4465     *           type: "post",
4466     *           dataType: "json",
4467     *           data: JSON.stringify({
4468     *                  "signature":signature.hex,
4469     *                  "containerId":"351d6f62-4653-48d8-8a41-6145b53f3921"
4470     *                  }),
4471     *           contentType: "application/json",
4472     *           headers: {"Authorization":"Basic YWRtaW46YWRtaW4="},
4473     *           success: function(data, textStatus, jqXHR){
4474     *                              alert('Archivo firmado correctamente: ' + data['signedFileId']);
4475     *           },
4476         *           error: function(jqXHR, textStatus, errorThrown){
4477         *                              alert('error en pdfs/resenas: ' + textStatus);
4478         *           }
4479     *  });
4480         *
4481         *
4482         *
4483         * @apiErrorExample {json} Error-Response:
4484         *     HTTP/1.1 401 Unauthorized
4485         *     {
4486         *       "error": "acceso no autorizado"
4487         *     }
4488         *     
4489         *     HTTP/1.1 404 Not Found
4490         *     {
4491         *       "error": "el contenedor con identificador containerId no existe ."
4492         *     }
4493         *         
4494         *     HTTP/1.1 500 Internal Server Error
4495         *     {
4496         *       "error": "Error en proceso de deserialización y completación de firma"
4497         *     }
4498
4499         *
4500         */
4501        @POST
4502        @Path("/bdocs/firmas/post")
4503        @Consumes(MediaType.APPLICATION_JSON)
4504        @Produces(MediaType.APPLICATION_JSON)   
4505        @Authenticator
4506        public Response postsignBDOCContainer(PostsignParameters postsignPar) throws IOException, MurachiException {
4507               
4508                logger.info("recurso /bdocs/firmas/post");
4509                String result = "";
4510               
4511                if (postsignPar == null) {
4512                // registrar error de firma en estadisticas
4513                        registerASignatureError(1);
4514                       
4515                        logger.error("solicitud mal formada.");
4516                        result = "\"error\":\"solicitud mal formada\"";
4517                        return Response.status(400).entity(result).build();     
4518                }
4519               
4520                // cadena con la firma
4521                String signature = postsignPar.getSignature();
4522                if (signature == null) {
4523                // registrar error de firma en estadisticas
4524                        registerASignatureError(1);
4525                       
4526                        logger.debug("signature == null");
4527                        logger.error("solicitud mal formada: no esta especificada la firma realizada en el cliente.");
4528                        result = "\"error\":\"solicitud mal formada: : no esta especificada la firma realizada en el cliente\"";
4529                        return Response.status(400).entity(result).build();
4530                }
4531                logger.info("firma en Hex: " + signature);
4532               
4533                // obtener el id del archivo a firmar
4534                String containerId = postsignPar.getContainerId();
4535                if (containerId == null) {
4536                // registrar error de firma en estadisticas
4537                        registerASignatureError(1);
4538                       
4539                        logger.debug("containerId == null");
4540                        logger.error("solicitud mal formada: no esta especificado el identificador del contenedor.");
4541                        result = "\"error\":\"solicitud mal formada: : no esta especificado el identificador del contenedor\"";
4542                        return Response.status(400).entity(result).build();
4543                }
4544                               
4545                String signedBdoc = containerId + ".bdoc";
4546                logger.debug("  sigendBdoc: " + signedBdoc);
4547               
4548                String serializedContainerId = SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized.bin";
4549                               
4550                System.out.println("serializedContainerId: " + serializedContainerId);
4551                logger.debug("  serializedContainerId: " + serializedContainerId);
4552               
4553                File f = new File(serializedContainerId);
4554               
4555                if (!f.exists()) {
4556                // registrar error de firma en estadisticas
4557                        registerASignatureError(1);
4558                       
4559                        logger.error("el contenedor "+ serializedContainerId + " no existe.");
4560                        result = "\"error\":\"el contenedor "+ serializedContainerId + " no existe\"";
4561                        return Response.status(404).entity(result).build();     
4562                }
4563               
4564                try {
4565                        Container deserializedContainer = deserialize(serializedContainerId);
4566                        logger.debug("  deserializado el contenedor "+ serializedContainerId);
4567                       
4568                        /*
4569                        if (deserializedContainer.getSignatures().size() > 0) {
4570                        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
4571                        deserializedContainer.save(byteOut);
4572                        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
4573                       
4574                        //Configuration configuration = initConfig(); // also need to re-initialize configuration settings
4575                       
4576                        Configuration configuration = new Configuration(Configuration.Mode.PROD);               
4577                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
4578                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);       
4579                       
4580                        Container container2 = Container.open(byteIn, configuration);
4581                       
4582                        byteOut.close();
4583                        byteIn.close();
4584                        //container2.sign(new PKCS12Signer("/tmp/ayzarra.p12", "ayzarra".toCharArray()));
4585                       
4586                        byte[] signatureInBytes = hexStringToByteArray(signature);
4587                               
4588                                container2.signRaw(signatureInBytes);
4589                                logger.debug("asignada firma al contenedor previamente firmado");
4590                       
4591                        System.out.println("********numero de firmas deserialize : "+ Integer.toString(container2.getSignatures().size()));
4592                       
4593                        serialize(container2, SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4594                                logger.debug(" serializado el contenedor: " + SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4595
4596                    }
4597                        else
4598                        {
4599                                // el contenedor no tiene firmas previas
4600                                byte[] signatureInBytes = hexStringToByteArray(signature);
4601                               
4602                                deserializedContainer.signRaw(signatureInBytes);
4603                                logger.debug("asignada firma al contenedor sin firmas previas");
4604                               
4605                                serialize(deserializedContainer, SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4606                                logger.debug(" serializado el contenedor: " + SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");                             
4607                        }
4608                        */
4609                       
4610                        byte[] signatureInBytes = hexStringToByteArray(signature);
4611                       
4612                        deserializedContainer.signRaw(signatureInBytes);
4613                        logger.debug("asignada firma al contenedor " + containerId );
4614                       
4615                        serialize(deserializedContainer, SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4616                        logger.debug(" serializado el contenedor: " + SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4617                       
4618                       
4619                       
4620                       
4621                        /*
4622                        //deserializedContainer.save(SERVER_UPLOAD_LOCATION_FOLDER + signedBdoc);
4623                        serialize(deserializedContainer, SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4624                        logger.debug(" serializado el contenedor: " + SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4625                        */
4626                       
4627                        /*
4628                        // prueba para evitar que las firmas tengan la misma hora de aplicacion
4629
4630                        // escribir el contendedor
4631                        deserializedContainer.save(SERVER_UPLOAD_LOCATION_FOLDER + containerId + ".bdoc");
4632                       
4633                        // abrir el contenedor
4634                        Configuration configuration = new Configuration(Configuration.Mode.PROD);                       
4635                        configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
4636                        configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);                   
4637                        Container c = Container.open(SERVER_UPLOAD_LOCATION_FOLDER + containerId + ".bdoc", configuration);
4638                        logger.debug("  contenedor abierto: " + SERVER_UPLOAD_LOCATION_FOLDER + containerId + ".bdoc");                 
4639                       
4640                        // serializar el contenedor
4641                        serialize(c, SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4642                        logger.debug("  serializado contenedor: " + SERVER_UPLOAD_LOCATION_FOLDER + containerId + "-serialized");
4643                        */
4644                       
4645                       
4646                        //c.save(SERVER_UPLOAD_LOCATION_FOLDER + containerId + ".bdoc");
4647                       
4648                        // eliminar el contenedor guardado
4649                        //File f = new File(SERVER_UPLOAD_LOCATION_FOLDER + containerId + ".bdoc");
4650                        //f.delete();
4651                       
4652                } catch (ClassNotFoundException e) {
4653                        //e.printStackTrace();
4654               
4655                        // registrar error de firma en estadisticas
4656                        registerASignatureError(1);
4657                       
4658                        JSONObject jsonError = new JSONObject();
4659                                               
4660                        System.out.println("ClassNotFoundException e: " + e.getMessage());
4661                        logger.error("error: " + e.getMessage());
4662                                                       
4663                        jsonError.put("error", e.getMessage());
4664                        return Response.status(500).entity(jsonError).build();                         
4665                } catch (DSSException e) {
4666                       
4667                // registrar error de firma en estadisticas
4668                        registerASignatureError(1);
4669                       
4670                        JSONObject jsonError = new JSONObject();
4671                       
4672                        System.out.println("DSSException e: " + e.getMessage());
4673                        logger.error("error: " + e.getMessage());
4674                                                       
4675                        jsonError.put("error", e.getMessage());
4676                        return Response.status(500).entity(jsonError).build();
4677                }
4678                               
4679                // en este punto el archivo bdoc debe estar disponible en la ruta
4680                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;             
4681                System.out.println("Archivo firmado correctamente");
4682                logger.debug("Archivo firmado correctamente");
4683                       
4684                PostsignMessage message = new PostsignMessage();
4685                message.setMessage("{\"signedFile\":"+ containerId);
4686                               
4687                JSONObject jsonFinalResult = new JSONObject();
4688                jsonFinalResult.put("signedFileId", containerId);
4689               
4690                logger.info(jsonFinalResult.toString());
4691               
4692                // registrar la firma exitosa en el contador de firmas
4693                registerASignature(1);
4694               
4695                return Response.status(200).entity(jsonFinalResult.toString()).build();
4696        }
4697       
4698       
4699
4700       
4701        /**
4702         * Crea un contenedor BDOC
4703         * @return contenedor BDOC creado
4704         */
4705        private Container createBDOCContainer() {
4706                logger.debug("createBDOCContainer() ");
4707                System.out.println("createBDOCContainer()");
4708               
4709                Container container = null;
4710               
4711                Configuration configuration = new Configuration(Configuration.Mode.PROD);
4712       
4713                configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
4714       
4715                configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
4716
4717               
4718                container = Container.create(Container.DocumentType.BDOC, configuration);
4719                System.out.println("container created");
4720                logger.debug("container created");
4721                               
4722                return container;               
4723        }
4724       
4725        /**
4726         * Abre un contenedor BDOC
4727         * @param pathToContainer ruta absoluta al contenedor BDOC
4728         * @return contenedor BDOC creado
4729         */
4730        private Container openBDOCContainer(String pathToContainer) {
4731                logger.debug("openBDOCContainer() ");
4732                System.out.println("openBDOCContainer()");
4733               
4734                Container container = null;
4735               
4736                Configuration configuration = new Configuration(Configuration.Mode.PROD);       
4737                configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
4738                configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
4739
4740                container = Container.open(pathToContainer, configuration);
4741               
4742                System.out.println("container opened");
4743                logger.debug("container "+ pathToContainer + " opened");
4744                               
4745                return container;               
4746        }
4747       
4748       
4749        /**
4750         * Agrega un archivo a un contendor BDOC existente
4751         * @param filePath ruta absoluta al archivo que se desea agregar
4752         * @param c contenedor BDOC al que se le desea agregar el archivo
4753         */
4754        private void addFileToBDOCContainer(String filePath, Container c) {
4755               
4756                logger.debug("addFileToBDOCContainer() ");
4757                System.out.println("addFileToBDOCContainer()");
4758                /*
4759                String mime = getMimeTypeWithTika(filePath);
4760                System.out.println("mimeType: " + mime);
4761               
4762                c.addDataFile(filePath, mime);
4763                System.out.println("agregado archivo a contenedor");
4764                */
4765               
4766        }
4767       
4768        /**
4769         * Agrega un archivo a un contenedor BDOC existente
4770         * @param is InputStream del archivo
4771         * @param fileName ruta del archivo que se desea agregar
4772         * @param mimeType tipo mime
4773         * @param c contenedor BDOC
4774         */
4775        private void addFileToBDOCContainer(InputStream is, String fileName, String mimeType, Container c) {
4776                logger.debug("addFileToBDOCContainer(InputStream) ");
4777                System.out.println("addFileToBDOCContainer(InputStream)");
4778               
4779               
4780                c.addDataFile(is, fileName, mimeType);
4781                System.out.println("agregado archivo a contenedor");
4782                logger.debug("agregado el archivo:  " + fileName + " al contenedor.");
4783        }
4784       
4785       
4786        /**
4787         * Elimina un archivo de un contenedor BDOC existente.
4788         *
4789         * Se debe pasar la ruta absoluta del archivo que se desea eliminar
4790         *
4791         * @param dataFile ruta absoluta del archivo que se desea eliminar
4792         * @param c contenedor BDOC del que se desea eliminar el archivo
4793         * @return si el archivo se elimino del contenedor
4794         */
4795        private boolean deleteDataFileFromBDOCContainer(String dataFile, Container c) {
4796                logger.debug("deleteDataFileFromBDOCContainer() ");
4797                System.out.println("deleteDataFileFromBDOCContainer()");               
4798               
4799                boolean result = false;
4800               
4801                // si el contenedor esta firmado no se puede eliminar un archivo
4802                if (c.getSignatures().size() > 0)
4803                {
4804                        logger.debug("el contenedor esta firmado y no se puede eliminar el archivo: "+ dataFile);
4805                        System.out.println("el contenedor esta firmado y no se puede eliminar el archivo: "+ dataFile);
4806                        result = false;
4807                }
4808                else
4809                {                       
4810                        int files = c.getDataFiles().size();
4811                        System.out.println("numero de archivos en el contenedor: " + Integer.toString(files));
4812                        if (files == 0)
4813                        {
4814                                logger.debug("el contendor no posee archivos");
4815                                System.out.println("el contenedor no posee archivos");
4816                                result = false;
4817                        }
4818                        else
4819                        {                               
4820                                c.removeDataFile(dataFile);
4821                                logger.debug("archivo eliminado del contenedor");
4822                                System.out.println("archivo eliminado del contenedor");
4823                                result = true;
4824                        }                       
4825                }
4826                return result;
4827        }
4828       
4829        /**
4830         * Elimina una firma del contendor BDOC.
4831         *
4832         * @param signatureId id de la firma que se desea eliminar. Las firmas se enumeran de 0 en adelante.
4833         * @param c Contenedor para eliminar la firma
4834         * @return si se eliminó la firma del contenedor
4835         */
4836        private boolean deleteSignatureFromBDOCContainer(int signatureId, Container c) {
4837                logger.debug("deleteSignatureFromBDOCContainer() ");
4838                System.out.println("deleteSignatureFromBDOCContainer()");               
4839               
4840                boolean result = false;
4841               
4842                // si el contenedor esta firmado no se puede eliminar un archivo
4843                int signatures = c.getSignatures().size();
4844                System.out.println("numero de firmas: "+ Integer.toString(signatures));
4845               
4846                if (signatures < 1)
4847                {
4848                        logger.debug("el contenedor no esta firmado; no se elimina ninguna firma");
4849                        System.out.println("el contenedor no esta firmado; no se elimina ninguna firma");
4850                        result = false;
4851                }
4852                else
4853                {                       
4854                        if ((signatureId >= signatures) || (signatureId < 0))
4855                        {
4856                                logger.debug("el id de firma a eliminar no es valido.");
4857                                System.out.println("el id de firma a eliminar no es valido");
4858                                result = false;
4859                        }
4860                        else
4861                        {
4862                                c.removeSignature(signatureId);
4863                                result = true;
4864                        }                       
4865                }
4866                return result;
4867        }
4868       
4869       
4870       
4871       
4872        private static void verifyBdocContainer(Container container) {
4873                logger.debug("verifyBdocContainer(Container container)");
4874               
4875            ValidationResult validationResult = container.validate();
4876
4877            List<DigiDoc4JException> exceptions = validationResult.getContainerErrors();
4878            boolean isDDoc = container.getDocumentType() == DocumentType.DDOC;
4879            for (DigiDoc4JException exception : exceptions) {
4880              if (isDDoc && isWarning(((DDocContainer) container).getFormat(), exception))
4881                System.out.println("    Warning: " + exception.toString());
4882              else
4883                System.out.println((isDDoc ? "  " : "   Error_: ") + exception.toString());
4884            }
4885
4886            if (isDDoc && (((ValidationResultForDDoc) validationResult).hasFatalErrors())) {
4887              return;
4888            }
4889
4890            List<Signature> signatures = container.getSignatures();
4891            if (signatures == null) {
4892              throw new SignatureNotFoundException();
4893            }
4894
4895            for (Signature signature : signatures) {
4896              List<DigiDoc4JException> signatureValidationResult = signature.validate();
4897              if (signatureValidationResult.size() == 0) {
4898                System.out.println("Signature " + signature.getId() + " is valid");
4899                logger.debug("Signature " + signature.getId() + " is valid");
4900              } else {
4901                System.out.println("Signature " + signature.getId() + " is not valid");
4902                logger.debug("Signature " + signature.getId() + " is not valid");
4903                for (DigiDoc4JException exception : signatureValidationResult) {
4904                  System.out.println((isDDoc ? "        " : "   Error: ")
4905                      + exception.toString());
4906                }
4907              }
4908              if (isDDoc && isDDocTestSignature(signature)) {
4909                System.out.println("Signature " + signature.getId() + " is a test signature");
4910                logger.debug("Signature " + signature.getId() + " is a test signature");
4911              }
4912            }
4913
4914            showWarnings(validationResult);
4915            verboseMessage(validationResult.getReport());
4916         }
4917
4918         private static void showWarnings(ValidationResult validationResult) {
4919                 if (bdocWarnings) {
4920                         for (DigiDoc4JException warning : validationResult.getWarnings()) {
4921                                 System.out.println("Warning: " + warning.toString());
4922                     }
4923                 }
4924         }
4925         
4926         /**
4927           * Checks is DigiDoc4JException predefined as warning for DDOC
4928           *
4929           * @param documentFormat format SignedDoc
4930           * @param exception      error to check
4931           * @return is this exception warning for DDOC utility program
4932           * @see SignedDoc
4933           */
4934          public static boolean isWarning(String documentFormat, DigiDoc4JException exception) {
4935            int errorCode = exception.getErrorCode();
4936            return (errorCode == DigiDocException.ERR_DF_INV_HASH_GOOD_ALT_HASH
4937                || errorCode == DigiDocException.ERR_OLD_VER
4938                || errorCode == DigiDocException.ERR_TEST_SIGNATURE
4939                || errorCode == DigiDocException.WARN_WEAK_DIGEST
4940                || (errorCode == DigiDocException.ERR_ISSUER_XMLNS && !documentFormat.equals(SignedDoc.FORMAT_SK_XML)));
4941          }
4942
4943          private static boolean isDDocTestSignature(Signature signature) {
4944                  CertValue certValue = ((DDocSignature) signature).getCertValueOfType(CertValue.CERTVAL_TYPE_SIGNER);
4945                  if (certValue != null) {
4946                          if (DigiDocGenFactory.isTestCard(certValue.getCert())) return true;
4947                  }
4948                  return false;
4949          }
4950         
4951          private static void verboseMessage(String message) {
4952                    if (bdocVerboseMode)
4953                      System.out.println(message);
4954          }
4955
4956       
4957
4958       
4959        /**
4960         * Retorna el mimeType del archivo pasado como argumento
4961         * @param absolutFilePath ruta absoluta del archivo
4962         * @return mimeType del archivo pasado como argumento
4963         */
4964        public String getMimeType(String absolutFilePath) {
4965                               
4966                String result = "";             
4967                java.nio.file.Path source = Paths.get(absolutFilePath);
4968                try {
4969                        result = Files.probeContentType(source);                       
4970                        System.out.println(result);
4971                } catch (IOException e) {
4972                        // TODO Auto-generated catch block
4973                        e.printStackTrace();
4974                }               
4975                return result;           
4976        }
4977       
4978        /**
4979         * Retorna el mimeType del archivo pasado como argumento
4980         * @param absolutFilePath ruta absoluta del archivo
4981         * @return mimeType del archivo pasado como argumento
4982         */
4983        public String getMimeTypeWithTika(String absolutFilePath) {
4984                               
4985                String mimeType = "";           
4986               
4987                Tika tika = new Tika();
4988                File file = new File(absolutFilePath);
4989                try {
4990                        mimeType = tika.detect(file);
4991                } catch (IOException e1) {
4992                        // TODO Auto-generated catch block
4993                        e1.printStackTrace();
4994                }
4995               
4996                /*
4997                java.nio.file.Path source = Paths.get(absolutFilePath);
4998                try {
4999                        result = Files.probeContentType(source);                       
5000                        System.out.println(result);
5001                } catch (IOException e) {
5002                        // TODO Auto-generated catch block
5003                        e.printStackTrace();
5004                }
5005                */             
5006                return mimeType;                 
5007        }
5008       
5009       
5010        /**
5011         * Convierte una cadena Hexadecimal en un arreglo de bytes
5012         * @param s cadena hexadecimal
5013         * @return arreglo de bytes resultantes de la conversion de la cadena hexadecimal
5014         */
5015        public static byte[] hexStringToByteArray(String s) {
5016            byte[] b = new byte[s.length() / 2];
5017            for (int i = 0; i < b.length; i++) {
5018              int index = i * 2;
5019              int v = Integer.parseInt(s.substring(index, index + 2), 16);
5020              b[i] = (byte) v;
5021            }
5022            return b;
5023          }
5024       
5025        /**
5026           * Converts a byte array into a hex string.
5027           * @param byteArray the byte array source
5028           * @return a hex string representing the byte array
5029           */
5030          public static String byteArrayToHexString(final byte[] byteArray) {
5031              if (byteArray == null) {
5032                  return "";
5033              }
5034              return byteArrayToHexString(byteArray, 0, byteArray.length);
5035          }
5036         
5037          public static String byteArrayToHexString(final byte[] byteArray, int startPos, int length) {
5038              if (byteArray == null) {
5039                  return "";
5040              }
5041              if(byteArray.length < startPos+length){
5042                  throw new IllegalArgumentException("startPos("+startPos+")+length("+length+") > byteArray.length("+byteArray.length+")");
5043              }
5044//            int readBytes = byteArray.length;
5045              StringBuilder hexData = new StringBuilder();
5046              int onebyte;
5047              for (int i = 0; i < length; i++) {
5048                  onebyte = ((0x000000ff & byteArray[startPos+i]) | 0xffffff00);
5049                  hexData.append(Integer.toHexString(onebyte).substring(6));
5050              }
5051              return hexData.toString();
5052          }
5053       
5054          /**
5055           * Serializa el contenedor BDOC pasado como argumento
5056           * @param container Contenedor que se desea serializar
5057           * @param filePath ruta absoluta al archivo serializado
5058           * @throws IOException
5059           */
5060          private static void serialize(Container container, String filePath) throws IOException {
5061                  FileOutputStream fileOut = new FileOutputStream(filePath+".bin");
5062                  ObjectOutputStream out = new ObjectOutputStream(fileOut);
5063                  out.writeObject(container);
5064                  out.flush();
5065                  out.close();
5066                  fileOut.close();
5067          }
5068         
5069          /**
5070           * Deserializa el contenedor BDOC pasado como argumento
5071           * @param filePath ruta absoluta al contenedor que se desea deserializar
5072           * @return contenedor deserializado
5073           * @throws IOException
5074           * @throws ClassNotFoundException
5075           */
5076          private static Container deserialize(String filePath) throws IOException, ClassNotFoundException {
5077                  //FileInputStream fileIn = new FileInputStream("container.bin");
5078                  FileInputStream fileIn = new FileInputStream(filePath);
5079                  ObjectInputStream in = new ObjectInputStream(fileIn);
5080                  Container container = (Container) in.readObject();
5081                  in.close();
5082                  fileIn.close();
5083                  return container;
5084          }
5085         
5086          /**
5087           * Deserializa el contenedor BDOC pasado como argumento. Verifica si el contenedor está
5088           * firmado para escribirlo y leerlo de nuevo.
5089           * @param filePath ruta absoluta al contenedor que se desea deserializar
5090           * @return contenedor deserializado
5091           * @throws IOException
5092           * @throws ClassNotFoundException
5093           *
5094           */
5095          private Container deserializer1(String filePath) throws IOException, ClassNotFoundException {
5096                  //FileInputStream fileIn = new FileInputStream("container.bin");
5097                  FileInputStream fileIn = new FileInputStream(filePath);
5098                  ObjectInputStream in = new ObjectInputStream(fileIn);
5099                  Container container = (Container) in.readObject();
5100                  in.close();
5101                  fileIn.close();
5102
5103                  if (container.getSignatures().size() > 0) {
5104                          ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
5105                          container.save(byteOut);
5106                          ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
5107
5108                          //Configuration configuration = initConfig(); // also need to re-initialize configuration settings
5109                          Configuration configuration = new Configuration(Configuration.Mode.PROD);             
5110                          configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
5111                          configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
5112                          Container container2 = Container.open(byteIn, configuration);
5113
5114                          byteOut.close();
5115                          byteIn.close();
5116                          return container2;
5117                  } else {
5118                          return container;
5119                  }
5120          }
5121         
5122
5123          /**
5124           * Retorna un JSON con estadisticas de uso del servicio.
5125           *
5126           * @return JSON con estadisticas de uso del servicio.
5127           *
5128           * @api {get} /Murachi/0.1/archivos/estadisticas Retorna estadísticas básicas de uso del servicio
5129           * @apiName GetEstatistics
5130           * @apiGroup General
5131           * @apiVersion 0.1.0
5132           *
5133           * @apiExample Example usage:
5134       * curl -i https://murachi.cenditel.gob.ve/Murachi/0.1/archivos/estadisticas -H "Authorization: Basic YWRtaW46YWRtaW4="
5135           *
5136           * @apiSuccess {String} numeroDeFirmasEjecutadas número de firmas electrónicas ejecutadas hasta la consulta
5137           * @apiSuccess {String} numeroDeFimasIncompletas número de firmas electrónicas incompletas hasta la consulta
5138           * @apiSuccess {String} numeroDeVerificaciones número de verificaciones de firma ejecutadas hasta la consulta
5139           */
5140          @GET
5141          @Path("/estadisticas")
5142          @Produces(MediaType.APPLICATION_JSON)
5143          @Authenticator
5144          public Response getStatisctics()  {
5145                 
5146                  logger.info("/estadisticas ");
5147                  String result = "";
5148                 
5149                  MURACHIStatistic statistic = new MURACHIStatistic(databaseHost, databasePort, databaseName, databaseLogin, databasePassword);
5150                 
5151                  /*
5152                  try {
5153                        statistic.createDatabaseTables();
5154                  } catch (InstantiationException | IllegalAccessException e) {
5155                          logger.error("error al crear la base de datos de estadisticas: " + e.getMessage());                   
5156                          result = "\"error\":\"no se pudo crear la base de datos de estadisticas del servicio.\"";
5157                          return Response.status(500).entity(result).build();
5158                  }
5159                  */
5160                                 
5161                  //statistic.incrementSignatures(0);
5162                 
5163                  int countSignatures = statistic.countOfSigantures();
5164                  logger.debug("fimas realizadas correctamente: "+ Integer.toString(countSignatures));
5165                 
5166                  JSONObject jsonObject = new JSONObject();
5167                  jsonObject.put("numeroDeFirmasEjecutadas", Integer.toString(countSignatures));
5168                 
5169                  int countSignaturesError = statistic.countOfSiganturesFailed();
5170                  jsonObject.put("numeroDeFimasIncompletas", Integer.toString(countSignaturesError));
5171                  logger.debug("firmas incorrectas: "+ Integer.toString(countSignaturesError));
5172                 
5173                  int countVerifications = statistic.countOfVerifications();
5174                  jsonObject.put("numeroDeVerificaciones", Integer.toString(countVerifications));
5175                  logger.debug("verificaciones realizadas correctamente: "+ Integer.toString(countVerifications));
5176                 
5177                  result = jsonObject.toString();
5178                 
5179                  return Response.status(200).entity(result).build();
5180          }
5181         
5182          /**
5183           * Registra un evento de firma electrónica en la base de datos de estadisticas
5184           * @param type 0-> PDF; 1->BDOC; 2->UNKN
5185           */
5186          private void registerASignature(int type) {
5187                        // registrar la verificacion exitosa en el contador de verificaciones
5188                          MURACHIStatistic statistic = new MURACHIStatistic(databaseHost, databasePort, databaseName, databaseLogin, databasePassword);
5189                          statistic.incrementSignatures(type);
5190                  }
5191         
5192          /**
5193           * Registra un evento de verificacion de firma electrónica en la base de datos de estadisticas
5194           * @param type 0-> PDF; 1->BDOC; 2->UNKN
5195           */
5196          private void registerAVerification(int type) {
5197                  // registrar la verificacion exitosa en el contador de verificaciones
5198                  MURACHIStatistic statistic = new MURACHIStatistic(databaseHost, databasePort, databaseName, databaseLogin, databasePassword);
5199                  statistic.incrementVerifications(type);                 
5200          }
5201         
5202          /**
5203           * Registra un evento de firma electrónica incompleta en la base de datos de estadisticas
5204           * @param type 0-> PDF; 1->BDOC; 2->UNKN
5205           */
5206          private void registerASignatureError(int type) {
5207                  // registrar la verificacion exitosa en el contador de verificaciones
5208                  MURACHIStatistic statistic = new MURACHIStatistic(databaseHost, databasePort, databaseName, databaseLogin, databasePassword);
5209                  statistic.incrementErrorSignatures(type);       
5210          }
5211     
5212         
5213       
5214         
5215       
5216         
5217        // ************************************************************************
5218        // ************************************************************************
5219        // ************************************************************************
5220         
5221         
5222       
5223
5224        // pruebas de funciones para gestionar un contenedor BDOC
5225               
5226                @GET
5227                @Path("/pruebaBDOC")
5228                @Produces("text/plain")
5229                public String testBDOCFunctions()  {
5230                       
5231                        Security.addProvider(new BouncyCastleProvider());
5232                       
5233                        Container c = createBDOCContainer();
5234                       
5235                        String containerId = UUID.randomUUID().toString();
5236                        System.out.println(containerId);
5237                       
5238                        if (c==null)
5239                        {
5240                                System.out.println("container == null");
5241                        }
5242                        else
5243                        {
5244                                System.out.println("container != null");
5245                        }
5246                       
5247                        addFileToBDOCContainer("/tmp/slides-93-cfrg-9.pdf", c);
5248                       
5249                        System.out.println("numero de archivos en el contenedor: " + Integer.toString(c.getDataFiles().size()));
5250                       
5251                        PKCS12Signer PKCS12_SIGNER = new PKCS12Signer("/tmp/tibisay.p12", "123456".toCharArray());
5252                       
5253                        SignatureParameters signatureParameters = new SignatureParameters();
5254                        SignatureProductionPlace productionPlace = new SignatureProductionPlace();
5255                        productionPlace.setCity("Merida");
5256                        productionPlace.setStateOrProvince("Merida");
5257                        productionPlace.setPostalCode("5101");
5258                        productionPlace.setCountry("Venezuela");
5259                        signatureParameters.setProductionPlace(productionPlace);
5260                        logger.debug("container setProductionPlace");
5261                        signatureParameters.setRoles(asList("Desarrollador"));
5262                        c.setSignatureParameters(signatureParameters);
5263                        c.setSignatureProfile(SignatureProfile.B_BES);
5264                       
5265                        c.sign(PKCS12_SIGNER);
5266                       
5267                       
5268                        if (deleteDataFileFromBDOCContainer("/tmp/slides-93-cfrg-9.pdf", c))
5269                        {
5270                                System.out.println("eliminado archivo del contenedor");
5271                        }
5272                        else
5273                        {
5274                                System.out.println("NO se eliminó el archivo del contenedor");
5275                        }
5276                               
5277                        if (deleteSignatureFromBDOCContainer(0, c))
5278                        {
5279                                System.out.println("SE ELIMINO la firma 2");
5280                        }
5281                        else
5282                        {
5283                                System.out.println("no se pudo eliminar la firma 0");
5284                        }
5285                       
5286                        System.out.println("numero de firmas restantes: "+ Integer.toString(c.getSignatures().size()));
5287                       
5288                        c.save("/tmp/prueba.bdoc");
5289                       
5290                        return "prueba exitosa";
5291                }
5292               
5293                @GET
5294                @Path("/serializar")
5295                @Produces("text/plain")
5296                public String serialize()  {
5297                       
5298                        logger.debug("recurso /serializar");
5299                       
5300                        Security.addProvider(new BouncyCastleProvider());
5301                       
5302                        Container c;
5303                        try {
5304                                c = deserialize("/tmp/container.bin");
5305                                logger.debug("deserializado contenedor");
5306                               
5307                                logger.debug("numero de firmas: "+ Integer.toString(c.getSignatures().size()));
5308                               
5309                                Security.addProvider(new BouncyCastleProvider());
5310                               
5311                                //c.sign(new PKCS12Signer("/tmp/ayzarra.p12", "ayzarra".toCharArray()));
5312                                                       
5313                                //c.save("/tmp/deserializado.bdoc");
5314                               
5315                                if (c.getSignatures().size() > 0) {
5316                                ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
5317                                c.save(byteOut);
5318                                ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
5319                               
5320                                //Configuration configuration = initConfig(); // also need to re-initialize configuration settings
5321                               
5322                                Configuration configuration = new Configuration(Configuration.Mode.PROD);               
5323                                configuration.loadConfiguration("/tmp/digidoc4j.yaml");
5324                                configuration.setTslLocation("file:///tmp/venezuela-tsl.xml");       
5325                               
5326                                Container container2 = Container.open(byteIn, configuration);
5327                                container2.sign(new PKCS12Signer("/tmp/ayzarra.p12", "ayzarra".toCharArray()));
5328                               
5329                                System.out.println("********numero de firmas deserialize : "+ Integer.toString(container2.getSignatures().size()));
5330                                container2.save("/tmp/deserializado2.bdoc");
5331
5332                            }
5333                               
5334                               
5335                               
5336                        } catch (ClassNotFoundException | IOException e) {
5337                                e.printStackTrace();
5338                               
5339                                logger.error("ClassNotFoundException | IOException e");
5340                                return "error ClassNotFoundException | IOException e";
5341                               
5342                        }
5343                       
5344                               
5345                        return "prueba exitosa";
5346                }
5347         
5348         
5349          /**
5350                 * Verifica si un archivo posee firmas electronicas y retorna informacion
5351                 * de las mismas en un json
5352                 * @param idFile
5353                 * @return
5354                 */
5355                @GET
5356                @Path("/verificar/{idFile}")
5357                //@Produces("application/json")
5358                @Produces("text/plain")
5359                public String verifyFile(@PathParam("idFile") String idFile) {
5360                       
5361                        String file = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
5362               
5363                        //return getMimeType(file);
5364                       
5365                                       
5366                        File tmpFile = new File(file);
5367                        String result = "";
5368
5369                       
5370                       
5371                       
5372                        if (tmpFile.exists()) {
5373                                result = "El archivo existe.";
5374                               
5375                                try {
5376                                        PdfReader reader = new PdfReader(file);
5377                                        AcroFields af = reader.getAcroFields();
5378                                        ArrayList<String> names = af.getSignatureNames();
5379                                        if (names.size() > 0) {
5380                                                result = "el archivo PDF posee "+ names.size() +" firma(s).\n";
5381                                               
5382                                                // sin esto explota: se debe agregar una implementacion del provider en tiempo de ejecucion
5383                                                //http://www.cs.berkeley.edu/~jonah/bc/org/bouncycastle/jce/provider/BouncyCastleProvider.html
5384                                                Security.addProvider(new BouncyCastleProvider());
5385                                               
5386                                                for (String name: names) {
5387                                                        result = result +"Nombre de la firma: "+ name + "\n";
5388                                                        System.out.println("Nombre de la firma: "+ name);
5389                                                       
5390                                                        PdfPKCS7 pk = af.verifySignature(name);
5391                                                       
5392                                                        Certificate[] pkc = pk.getCertificates();
5393                                                       
5394                                                        String tmpSignerName = pk.getSigningCertificate().getSubjectX500Principal().toString();
5395                                                       
5396                                                       
5397                                                        result = result + "Sujeto del certificado firmante: " + tmpSignerName + "\n"; 
5398                                                        //pk.getSigningCertificate().getSubjectX500Principal().getName() + "\n";
5399                                                        System.out.println("Sujeto del certificado firmante: " + 
5400                                                                        pk.getSigningCertificate().getSubjectX500Principal().toString());
5401                                                         
5402                                                        Calendar cal = pk.getSignDate();
5403                                                       
5404                                                        SimpleDateFormat date_format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
5405                                                       
5406                                                        //result = result + "Fecha de la firma: " + cal.toString() + "\n";
5407                                                        result = result + "Fecha de la firma: " + date_format.format(cal.getTime()) + "\n";
5408                                                       
5409                                                        /*
5410                                                        System.out.println("año: "+ cal.get(Calendar.YEAR));
5411                                                        System.out.println("mes: "+ (cal.get(Calendar.MONTH) + 1));
5412                                                        System.out.println("día: "+ cal.get(Calendar.DAY_OF_MONTH));
5413                                                        System.out.println("hora: "+ cal.get(Calendar.HOUR));
5414                                                        System.out.println("minuto: "+ cal.get(Calendar.MINUTE));
5415                                                        System.out.println("segundo: "+ cal.get(Calendar.SECOND));
5416                                                        */
5417                                                        //SimpleDateFormat date_format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
5418                                                    System.out.println(date_format.format(cal.getTime()));
5419
5420                                                }
5421                                               
5422                                               
5423                                        }else{
5424                                                result = "el archivo PDF no posee firmas";
5425                                        }
5426                                       
5427                                       
5428                                       
5429                                } catch (IOException e) {
5430
5431                                        e.printStackTrace();
5432                                }
5433                               
5434                               
5435                        }else {
5436                                result = "El archivo NO existe.";
5437                        }
5438                       
5439                       
5440                        return result;
5441                       
5442                       
5443                } 
5444         
5445       
5446       
5447        /**
5448         * Ejecuta el proceso de presign o preparacion de firma de documento pdf
5449         * @param presignPar
5450         * @param req objeto request para crear una sesion y mantener elementos del
5451         * pdf en la misma
5452         * @param resp
5453         */
5454        @POST
5455        @Path("/prepararfirmapdf")
5456        @Consumes(MediaType.APPLICATION_JSON)
5457        @Produces(MediaType.APPLICATION_JSON)
5458        //public Response presign(PresignParameters presignPar, @Context HttpServletRequest req) {
5459        public PresignHash presign(PresignParameters presignPar, @Context HttpServletRequest req) {
5460               
5461
5462                // cadena resultado de la funcion
5463                String result = "";
5464               
5465                PresignHash presignHash = new PresignHash();
5466               
5467               
5468                // cadena con el certificado
5469                String certHex = presignPar.getCertificate();
5470                System.out.println("certificado en Hex: " + certHex);
5471               
5472                // obtener el id del archivo
5473                String fileId = presignPar.getFileId();
5474                               
5475                try {
5476                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
5477                        Certificate[] chain = new Certificate[1];
5478                       
5479                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
5480                        chain[0] = factory.generateCertificate(in);
5481                       
5482                        if (chain[0] == null) {
5483                                System.out.println("error chain[0] == null");
5484                        }else {
5485                               
5486                                System.out.println("se cargo el certificado correctamente");
5487                                System.out.println(chain[0].toString());
5488                        }
5489                       
5490                        //String pdf = SERVER_UPLOAD_LOCATION_FOLDER + "e27a6a90-f955-4191-8e54-580e316a999d";
5491                        String pdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
5492                        System.out.println("archivo a firmar: " + pdf);
5493                       
5494                        PdfReader reader = new PdfReader(pdf);
5495                       
5496                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
5497                       
5498                        //FileOutputStream baos = new FileOutputStream(pdf+"-signed.pdf");
5499                       
5500                        PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
5501                       
5502                        // crear la apariencia de la firma
5503                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
5504                sap.setReason("Prueba de firma en dos partes");
5505                sap.setLocation("Merida, Venezuela");
5506                sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
5507                sap.setCertificate(chain[0]);
5508               
5509                // crear la estructura de la firma
5510                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
5511                dic.setReason(sap.getReason());
5512                dic.setLocation(sap.getLocation());
5513                dic.setContact(sap.getContact());
5514                dic.setDate(new PdfDate(sap.getSignDate()));
5515               
5516                sap.setCryptoDictionary(dic);
5517               
5518                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
5519                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
5520                sap.preClose(exc);
5521               
5522                ExternalDigest externalDigest = new ExternalDigest() {
5523                        public MessageDigest getMessageDigest(String hashAlgorithm)
5524                        throws GeneralSecurityException {
5525                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
5526                        }
5527                };
5528                       
5529                       
5530                PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
5531               
5532                InputStream data = sap.getRangeStream();
5533               
5534                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
5535               
5536                Calendar cal = Calendar.getInstance();
5537                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
5538               
5539                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
5540               
5541                System.out.println("sh length: "+ sh.length);
5542                       
5543                String hashToSign = byteArrayToHexString(sh);
5544                System.out.println("***************************************************************");
5545                System.out.println("HASH EN HEXADECIMAL:");
5546                System.out.println(hashToSign);
5547                System.out.println("length: " +hashToSign.length());   
5548                System.out.println("***************************************************************");
5549                       
5550                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
5551                        Date date = new Date();
5552                        System.out.println(dateFormat.format(date));
5553                        //String d = dateFormat.format(date);
5554                       
5555                       
5556                        // almacenar los objetos necesarios para realizar el postsign en una sesion
5557                        HttpSession session = req.getSession(true);
5558                        session.setAttribute("hashToSign", hashToSign);
5559                       
5560                        session.setAttribute("stamper", stamper);
5561                        session.setAttribute("sgn", sgn);
5562                        session.setAttribute("hash", hash);
5563                        session.setAttribute("cal", cal);
5564                        session.setAttribute("sap", sap);
5565                        session.setAttribute("baos", baos);
5566                        session.setAttribute("fileId", fileId);
5567                       
5568                        // creacion del json
5569                        JSONObject jsonHash = new JSONObject();
5570                        jsonHash.put("hashToSign", hashToSign);
5571                       
5572                        result = jsonHash.toString();
5573                       
5574                        presignHash.setHash(hashToSign);
5575                               
5576                       
5577                } catch (CertificateException e1) {
5578                        // TODO Auto-generated catch block
5579                        e1.printStackTrace();
5580                } catch (IOException e) {
5581                        // TODO Auto-generated catch block
5582                        e.printStackTrace();
5583                } catch (DocumentException e) {
5584                        // TODO Auto-generated catch block
5585                        e.printStackTrace();
5586                } catch (InvalidKeyException e) {
5587                        // TODO Auto-generated catch block
5588                        e.printStackTrace();
5589                } catch (NoSuchProviderException e) {
5590                        // TODO Auto-generated catch block
5591                        e.printStackTrace();
5592                } catch (NoSuchAlgorithmException e) {
5593                        // TODO Auto-generated catch block
5594                        e.printStackTrace();
5595                } catch (GeneralSecurityException e) {
5596                        // TODO Auto-generated catch block
5597                        e.printStackTrace();
5598                }
5599               
5600                //return Response.status(200).entity(result).build();
5601                return presignHash;
5602                       
5603        }
5604       
5605       
5606        /**
5607         * Ejecuta el proceso de postsign o completacion de firma de documento pdf
5608         * @param postsignPar
5609         * @param req objeto request para crear una sesion y mantener elementos del
5610         * pdf en la misma
5611         * @param resp
5612         * @throws IOException
5613         */
5614        @POST
5615        @Path("/completarfirmapdf")
5616        @Consumes(MediaType.APPLICATION_JSON)
5617        @Produces(MediaType.APPLICATION_JSON)
5618        public Response postsign(PostsignParameters postsignPar, @Context HttpServletRequest req) throws IOException {
5619               
5620               
5621                // cadena resultado de la funcion
5622                String result = "";
5623                               
5624                // cadena con la firma
5625                String signature = postsignPar.getSignature();
5626                System.out.println("firma en Hex: " + signature);
5627               
5628                HttpSession session = req.getSession(false);
5629               
5630                String fileId = (String) session.getAttribute("fileId");
5631                System.out.println("fileId: " + fileId);
5632               
5633                PdfStamper stamper = (PdfStamper) session.getAttribute("stamper");
5634               
5635                PdfPKCS7 sgn = (PdfPKCS7) session.getAttribute("sgn");
5636               
5637                byte[] hash = (byte[]) session.getAttribute("hash");
5638               
5639                Calendar cal = (Calendar) session.getAttribute("cal");
5640               
5641                PdfSignatureAppearance sap = (PdfSignatureAppearance) session.getAttribute("sap");
5642               
5643                ByteArrayOutputStream os = (ByteArrayOutputStream) session.getAttribute("baos");
5644               
5645                if (sgn == null) {
5646                        System.out.println("sgn == null");
5647                }
5648                if (hash == null) {
5649                        System.out.println("hash == null");
5650                }
5651                if (cal == null) {
5652                        System.out.println("cal == null");
5653                }
5654                if (sap == null) {
5655                        System.out.println("sap == null");
5656                }
5657                if (os == null) {
5658                        System.out.println("os == null");
5659                }
5660               
5661               
5662               
5663                // convertir signature en bytes         
5664                byte[] signatureInBytes = hexStringToByteArray(signature);
5665                               
5666                // completar el proceso de firma
5667                sgn.setExternalDigest(signatureInBytes, null, RSA_DIGEST_ENCRYPTION_ALGORITHM);
5668                byte[] encodeSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
5669                byte[] paddedSig = new byte[8192];
5670                System.arraycopy(encodeSig, 0, paddedSig, 0, encodeSig.length);
5671                PdfDictionary dic2 = new PdfDictionary();
5672                dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
5673                try {
5674                        sap.close(dic2);
5675                       
5676                        stamper.close();
5677                        System.out.println("stamper.close");
5678                       
5679                }catch(DocumentException e) {
5680                       
5681                        System.out.println("throw new IOException");
5682                        throw new IOException(e);
5683                       
5684                } catch (IOException e) {
5685                        // TODO Auto-generated catch block
5686                        System.out.println("IOException e");
5687                        e.printStackTrace();
5688                       
5689                }
5690               
5691                String signedPdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf";
5692               
5693                FileOutputStream signedFile = new FileOutputStream(signedPdf);
5694               
5695                os.writeTo(signedFile);
5696                os.flush();
5697               
5698               
5699               
5700                // en este punto el archivo pdf debe estar disponible en la ruta
5701                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;
5702               
5703                // llamar a una funcion que permita descargar el archivo
5704               
5705                result = "Archivo firmado correctamente";
5706                System.out.println("Archivo firmado correctamente");
5707               
5708                return Response.status(200).entity(result).build();
5709        }
5710       
5711        /**
5712         * Ejecuta el proceso de presign o preparacion de firma de documento en formato BDOC
5713         *
5714         * @param presignPar
5715         * @param req
5716         * @return
5717         */
5718        @POST
5719        @Path("/bdoc/")
5720        @Consumes(MediaType.APPLICATION_JSON)
5721        @Produces(MediaType.APPLICATION_JSON)
5722        public PresignHash presignBdoc2(PresignParameters presignPar, @Context HttpServletRequest req) {
5723               
5724                System.out.println("presignBdoc2: ");
5725               
5726               
5727                String fileId;
5728                String certHex;
5729               
5730                CertificateFactory cf;
5731                X509Certificate signerCert;
5732               
5733                // cadena resultado de la funcion
5734                String result = "";
5735                               
5736                PresignHash presignHash = new PresignHash();
5737               
5738                SignedInfo signedInfo;
5739               
5740                fileId = presignPar.getFileId();
5741                String sourceFile = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
5742               
5743                certHex = presignPar.getCertificate();
5744                System.out.println("certificado en Hex: " + certHex);
5745               
5746//              try {
5747                        /*             
5748                        Configuration configuration = new Configuration(Configuration.Mode.TEST);
5749                       
5750                        configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
5751                        configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
5752                   
5753                        Container container = Container.create(configuration);
5754                    SignatureParameters signatureParameters = new SignatureParameters();
5755                    SignatureProductionPlace productionPlace = new SignatureProductionPlace();
5756                    productionPlace.setCity("Merida");
5757                    signatureParameters.setProductionPlace(productionPlace);
5758                    signatureParameters.setRoles(asList("Desarrollador"));
5759                    container.setSignatureParameters(signatureParameters);
5760                    container.setSignatureProfile(SignatureProfile.B_BES);
5761                    container.addDataFile("/tmp/215d6ef7-d639-4191-87a1-ef68a91b2b27", "text/plain");
5762                    container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
5763//                  Container container = Container.open("util/faulty/bdoc21-bad-nonce-content.bdoc");
5764                    container.save("/tmp/signed.bdoc");
5765                    ValidationResult results = container.validate();
5766                    System.out.println(results.getReport());
5767                        */
5768
5769                       
5770                Security.addProvider(new BouncyCastleProvider());
5771                        System.setProperty("digidoc4j.mode", "TEST");
5772                       
5773                        Configuration configuration;
5774                        configuration = new Configuration(Configuration.Mode.TEST);
5775                        //configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
5776                       
5777                        //configuration.setTslLocation("https://tibisay.cenditel.gob.ve/murachi/raw-attachment/wiki/WikiStart/trusted-test-mp.xml");
5778                        configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
5779                       
5780                        Container container;
5781                       
5782                        container = Container.create(Container.DocumentType.BDOC, configuration);
5783                       
5784                        SignatureParameters signatureParameters = new SignatureParameters();
5785                    SignatureProductionPlace productionPlace = new SignatureProductionPlace();
5786                    productionPlace.setCity("Merida");
5787                    signatureParameters.setProductionPlace(productionPlace);
5788                    signatureParameters.setRoles(asList("Desarrollador"));
5789                    container.setSignatureParameters(signatureParameters);
5790                    container.setSignatureProfile(SignatureProfile.B_BES);
5791                       
5792                        container.addDataFile(sourceFile, "text/plain");
5793                       
5794                        container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
5795                    container.save("/tmp/signed.bdoc");
5796                    ValidationResult results = container.validate();
5797                    System.out.println(results.getReport());
5798                       
5799                        /*
5800                        cf = CertificateFactory.getInstance("X.509");
5801               
5802                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
5803                       
5804                        signerCert = (X509Certificate) cf.generateCertificate(in);
5805                       
5806                        signedInfo = container.prepareSigning(signerCert);
5807                       
5808                        String hashToSign = byteArrayToHexString(signedInfo.getDigest());
5809                        //System.out.println("presignBdoc - hash: " + byteArrayToHexString(signedInfo.getDigest()));
5810                        System.out.println("presignBdoc - hash: " + hashToSign);
5811                       
5812                       
5813                        //container.save("/tmp/containerTmp.bdoc");
5814                        serialize(container, "/tmp/containerSerialized");
5815                        */
5816                       
5817                        String hashToSign = "firma exitosa";
5818                       
5819                        // creacion del json
5820                        JSONObject jsonHash = new JSONObject();
5821                        jsonHash.put("hashToSign", hashToSign);
5822                                               
5823                        result = jsonHash.toString();
5824                                               
5825                        presignHash.setHash(hashToSign);
5826                       
5827                       
5828/*                     
5829                } catch (CertificateException e1) {
5830                        // TODO Auto-generated catch block
5831                        e1.printStackTrace();
5832                } catch (IOException e) {
5833                        // TODO Auto-generated catch block
5834                        e.printStackTrace();
5835                }
5836*/             
5837               
5838                return presignHash;
5839               
5840        }
5841       
5842       
5843        @GET
5844        @Path("/testbdoc/")
5845        public String testBdoc() {
5846               
5847                Security.addProvider(new BouncyCastleProvider());
5848               
5849                Configuration configuration = new Configuration(Configuration.Mode.PROD);
5850               
5851                configuration.loadConfiguration("/tmp/digidoc4j.yaml");
5852                //configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
5853                configuration.setTslLocation("file:///tmp/venezuela-tsl.xml");
5854               
5855            Container container = Container.create(configuration);
5856            SignatureParameters signatureParameters = new SignatureParameters();
5857            SignatureProductionPlace productionPlace = new SignatureProductionPlace();
5858            productionPlace.setCity("Merida");
5859            signatureParameters.setProductionPlace(productionPlace);
5860            signatureParameters.setRoles(asList("Desarrollador"));
5861            container.setSignatureParameters(signatureParameters);
5862            container.setSignatureProfile(SignatureProfile.B_BES);
5863            container.addDataFile("/tmp/salida.txt", "text/plain");
5864            container.sign(new PKCS12Signer("/tmp/tibisay.p12", "123456".toCharArray()));
5865//          Container container = Container.open("util/faulty/bdoc21-bad-nonce-content.bdoc");
5866            container.save("/tmp/signed.bdoc");
5867            ValidationResult result = container.validate();
5868            System.out.println(result.getReport());
5869               
5870                return "test";
5871        }
5872       
5873        /**
5874         * Prueba de agregar una firma electrónica a un contenedor existente.
5875         *
5876         * NOTA: A un contenedor que posee una firma no se le pueden agregar nuevos DataFiles.
5877         * @return
5878         */
5879        @GET
5880        @Path("/addsignaturebdoc/")
5881        public String addSignatureBdoc() {
5882                logger.debug("/addsignaturebdoc/");
5883               
5884                Security.addProvider(new BouncyCastleProvider());
5885               
5886                Configuration configuration = new Configuration(Configuration.Mode.PROD);
5887               
5888                configuration.loadConfiguration(DIGIDOC4J_CONFIGURATION);
5889               
5890                configuration.setTslLocation(DIGIDOC4J_TSL_LOCATION);
5891                               
5892                //String bdocFile = "/tmp/c1d099ad-44b3-4227-82fa-8c8f03746787.bdoc";
5893                String bdocFile = "/tmp/twoSignatures.bdoc";
5894               
5895                Container container = Container.open(bdocFile, configuration);
5896                logger.debug("open container: "+ bdocFile);
5897               
5898            SignatureParameters signatureParameters = new SignatureParameters();
5899           
5900            SignatureProductionPlace productionPlace = new SignatureProductionPlace();
5901            productionPlace.setCity("Merida");
5902            productionPlace.setStateOrProvince("Merida");
5903            productionPlace.setPostalCode("5101");
5904            productionPlace.setCountry("Venezuela");
5905           
5906            signatureParameters.setProductionPlace(productionPlace);
5907           
5908            signatureParameters.setRoles(asList("Desarrollador"));
5909           
5910            container.setSignatureParameters(signatureParameters);
5911           
5912            container.setSignatureProfile(SignatureProfile.B_BES);
5913                   
5914            logger.debug("signing: "+ bdocFile);
5915            container.sign(new PKCS12Signer("/tmp/tibisay.p12", "123456".toCharArray()));
5916
5917            String outputFile = "/tmp/threeSignatures.bdoc";
5918            container.save(outputFile);
5919            logger.debug("saved file in : "+ outputFile);
5920           
5921            ValidationResult result = container.validate();
5922            System.out.println(result.getReport());
5923               
5924                return "success";
5925        }
5926       
5927       
5928       
5929        /**
5930         * Prueba de ejecucion de programa desde consola. Incompleta
5931         * @return
5932         * @throws InterruptedException
5933         */
5934        @GET
5935        @Path("/ejecutar")
5936        @Produces("text/plain")
5937        public String executeProcess() throws InterruptedException {
5938               
5939                String s = "9712f235-4dd4-4b09-957d-b06c33af482b-serialized.bin";
5940                String[] array = s.split("-serialized\\.bin");
5941               
5942                return array[0];
5943               
5944               
5945               
5946                /*
5947                String line = "";
5948                OutputStream stdin = null;
5949                InputStream stderr = null;
5950                InputStream stdout = null;
5951               
5952                try {
5953                        System.out.print("...a crear el proceso");
5954                        Process process = Runtime.getRuntime().exec("/usr/java/jdk1.7.0_21/bin/java -jar /home/aaraujo/desarrollo/2015/servicioVerificacion/testsigningpdf/holamundopdf.jar /tmp/589750.pdf /tmp/simonDiaz.pem /tmp/firmadoconsola.pdf");
5955                        //Process process = Runtime.getRuntime().exec("ls -l");
5956                        stdin = process.getOutputStream();
5957                        stderr = process.getErrorStream();
5958                        stdout = process.getInputStream();
5959                       
5960                        InputStreamReader isr = new InputStreamReader(stdout);
5961                        BufferedReader buff = new BufferedReader (isr);
5962
5963                       
5964                        while((line = buff.readLine()) != null)
5965                                System.out.print(line+"\n");
5966                        int exitValue = process.waitFor();
5967                        if (exitValue != 0) {
5968                            System.out.println("Abnormal process termination");
5969                        }       
5970                       
5971                } catch (IOException e) {
5972                        // TODO Auto-generated catch block
5973                        e.printStackTrace();
5974                }
5975                System.out.print("...saliendo");
5976                return line;
5977                */
5978        }
5979       
5980       
5981       
5982       
5983       
5984        /**
5985         *
5986         * @param certHex
5987         * @param httpHeaders
5988         * @param req
5989         * @param resp
5990         */
5991        @POST
5992        @Path("/presignOld")
5993        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
5994        public void presignOld(
5995                        @FormParam("certHexInForm") String certHex,
5996                        @Context HttpHeaders httpHeaders,
5997                        @Context HttpServletRequest req,
5998                        @Context HttpServletResponse resp) {
5999               
6000
6001                String host = httpHeaders.getRequestHeader("host").get(0);
6002               
6003                String agent = httpHeaders.getRequestHeader("user-agent").get(0);
6004                String salida = "User agent :"+ agent +" from host : "+host;
6005                System.out.println(host);
6006                System.out.println(agent);
6007                System.out.println(salida);
6008               
6009                System.out.println("certificado en Hex: " + certHex);
6010               
6011                try {
6012                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
6013                        Certificate[] chain = new Certificate[1];
6014                       
6015                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
6016                        chain[0] = factory.generateCertificate(in);
6017                       
6018                        if (chain[0] == null) {
6019                                System.out.println("error chain[0] == null");
6020                        }else {
6021                               
6022                                System.out.println("se cargo el certificado correctamente");
6023                                System.out.println(chain[0].toString());
6024                        }
6025                       
6026                        String pdf = SERVER_UPLOAD_LOCATION_FOLDER + "e27a6a90-f955-4191-8e54-580e316a999d";
6027                       
6028                        PdfReader reader = new PdfReader(pdf);
6029                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
6030                        PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
6031                       
6032                        // crear la apariencia de la firma
6033                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
6034                sap.setReason("Prueba de firma en dos partes");
6035                sap.setLocation("Merida, Venezuela");
6036                sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
6037                sap.setCertificate(chain[0]);
6038               
6039                // crear la estructura de la firma
6040                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
6041                dic.setReason(sap.getReason());
6042                dic.setLocation(sap.getLocation());
6043                dic.setContact(sap.getContact());
6044                dic.setDate(new PdfDate(sap.getSignDate()));
6045               
6046                sap.setCryptoDictionary(dic);
6047               
6048                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
6049                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
6050                sap.preClose(exc);
6051               
6052                ExternalDigest externalDigest = new ExternalDigest() {
6053                        public MessageDigest getMessageDigest(String hashAlgorithm)
6054                        throws GeneralSecurityException {
6055                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
6056                        }
6057                };
6058                       
6059                       
6060                PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
6061               
6062                InputStream data = sap.getRangeStream();
6063               
6064                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
6065               
6066                Calendar cal = Calendar.getInstance();
6067                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
6068               
6069                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
6070               
6071                System.out.println("sh length: "+ sh.length);
6072                       
6073                String hashToSign = byteArrayToHexString(sh);
6074                System.out.println("***************************************************************");
6075                System.out.println("HASH EN HEXADECIMAL:");
6076                System.out.println(hashToSign);
6077                System.out.println("length: " +hashToSign.length());   
6078                System.out.println("***************************************************************");
6079                       
6080                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
6081                        Date date = new Date();
6082                        System.out.println(dateFormat.format(date));
6083                        String d = dateFormat.format(date);
6084                       
6085                       
6086                        // almacenar los objetos necesarios para realizar el postsign en una sesion
6087                        HttpSession session = req.getSession(true);
6088                        session.setAttribute("hashToSign", hashToSign);
6089                       
6090                        session.setAttribute("sgn", sgn);
6091                        session.setAttribute("hash", hash);
6092                        session.setAttribute("cal", cal);
6093                        session.setAttribute("sap", sap);
6094                        session.setAttribute("baos", baos);
6095                       
6096               
6097                       
6098                        resp.sendRedirect("http://localhost/murachi2.html");
6099                       
6100                       
6101                } catch (CertificateException e1) {
6102                        // TODO Auto-generated catch block
6103                        e1.printStackTrace();
6104                } catch (IOException e) {
6105                        // TODO Auto-generated catch block
6106                        e.printStackTrace();
6107                } catch (DocumentException e) {
6108                        // TODO Auto-generated catch block
6109                        e.printStackTrace();
6110                } catch (InvalidKeyException e) {
6111                        // TODO Auto-generated catch block
6112                        e.printStackTrace();
6113                } catch (NoSuchProviderException e) {
6114                        // TODO Auto-generated catch block
6115                        e.printStackTrace();
6116                } catch (NoSuchAlgorithmException e) {
6117                        // TODO Auto-generated catch block
6118                        e.printStackTrace();
6119                } catch (GeneralSecurityException e) {
6120                        // TODO Auto-generated catch block
6121                        e.printStackTrace();
6122                }
6123               
6124               
6125       
6126        }
6127       
6128       
6129        @POST
6130        @Path("/postsign")
6131        public String postsignOld(@Context HttpServletRequest req,
6132                        @Context HttpServletResponse resp) {
6133               
6134                System.out.println("...postsign()...");
6135               
6136                HttpSession session = req.getSession(false);
6137                Object att = session.getAttribute("hashToSign");
6138                               
6139       
6140                String output = "atributo leido de la sesion: " + att.toString();
6141               
6142               
6143                return output;
6144                //return Response.status(200).entity(output).build();
6145        }
6146       
6147       
6148        @GET
6149        @Path("/retornajson")
6150        @Produces(MediaType.APPLICATION_JSON)
6151        public PresignHash retornajson(@Context HttpServletRequest req) {
6152               
6153               
6154               
6155                PresignHash h = new PresignHash();
6156                h.setHash("ESTO SERIA UN HASH");
6157               
6158                System.out.println("...retornajson..."+ h.getHash());
6159               
6160                return h;
6161               
6162        }
6163       
6164        @POST
6165        @Path("/enviarjson")
6166        @Consumes(MediaType.APPLICATION_JSON)
6167        @Produces(MediaType.APPLICATION_JSON)
6168        public PresignHash recibejson( PresignParameters par) {
6169               
6170                String fileId = par.getFileId();
6171                System.out.println("...fileId recibido..."+ fileId);
6172               
6173                String cert = par.getCertificate();
6174                System.out.println("...certificate recibido..."+ cert);
6175               
6176                PresignHash h = new PresignHash();
6177                h.setHash("DEBES FIRMAR ESTO");
6178               
6179                System.out.println("...recibejson..."+ h.getHash());
6180               
6181                return h;
6182               
6183        }
6184       
6185       
6186        @POST
6187        @Path("/phpcargas")
6188        @Consumes(MediaType.MULTIPART_FORM_DATA)
6189        @Produces(MediaType.APPLICATION_JSON)
6190        @Authenticator
6191        public Response uploadPHP(FormDataMultiPart formParams) throws MurachiException {
6192               
6193                logger.info("recurso /phpcargas");
6194                logger.debug("  uploadPHP...");
6195               
6196                // cadena con la respuesta
6197                String result = "";
6198               
6199                String fileId = "";
6200               
6201                if (formParams == null) {
6202                        logger.error("solicitud mal formada.");
6203                        result = "\"error\":\"solicitud mal formada\"";
6204                        return Response.status(400).entity(result).build();
6205                }
6206               
6207                Map<String, List<FormDataBodyPart>> fieldsByName = formParams.getFields();
6208                logger.debug("  contenido de Map: " + Integer.toString(fieldsByName.size()));
6209               
6210                for (List<FormDataBodyPart> fields : fieldsByName.values())
6211            {
6212                for (FormDataBodyPart field : fields)
6213                {
6214                    InputStream is = field.getEntityAs(InputStream.class);
6215                   
6216                    if (is == null) 
6217                    {
6218                        logger.debug("is: null");
6219                        result = "\"error\":\"archivo pasado al recurso es nulo.\"";
6220                                return Response.status(500).entity(result).build();
6221                    }             
6222                   
6223                    FormDataContentDisposition file = field.getFormDataContentDisposition();               
6224                    String fileName = file.getFileName();
6225                    logger.debug("fileName: " + fileName);                 
6226                    /*
6227                    if (fileName == null)
6228                    {
6229                        logger.debug("fileName: null");
6230                        result = "\"error\":\"nombre del archivo pasado al recurso es nulo. Debe especificar un nombre de archivo.\"";
6231                                return Response.status(500).entity(result).build();
6232                    }               
6233                   
6234                    String mimeType = field.getMediaType().toString();                             
6235                    logger.debug("mimeType: " + mimeType);
6236                   
6237                    if (mimeType == null)
6238                    {
6239                        logger.debug("mimeType: null");
6240                        result = "\"error\":\"tipo mime del archivo pasado al recurso es nulo.\"";
6241                                return Response.status(500).entity(result).build();
6242                    }
6243                    */
6244                                                   
6245                    try
6246                    {
6247                        //addFileToBDOCContainer(is, fileName, mimeType, c);
6248                       
6249                        fileId = UUID.randomUUID().toString();
6250                                System.out.println(fileId);
6251                               
6252                                saveToDisk(is, null, fileId);
6253                        logger.info("se guardó el archivo" + fileId + "en el disco");
6254                    }
6255                    catch(Exception e) 
6256                    {
6257                        logger.debug("excepcion: " + e.getMessage());                   
6258                                result = "\"error\":\"no se pudo guardar el archivo en el servidor.\"";
6259                                return Response.status(500).entity(result).build();
6260                    }               
6261                                   
6262                }
6263            }           
6264               
6265                //logger.debug("cantidad de DataFile del contenedor: " + Integer.toString(c.getDataFiles().size()));
6266                //String fileId = UUID.randomUUID().toString();
6267                //System.out.println("id contenedor serializado: "+fileId);
6268                               
6269                // establecer el nombre del archivo a serializar
6270                //String serializedContainerId = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-serialized";
6271                //logger.debug("        id de contenedor serializado: "+ serializedContainerId);
6272       
6273                result = "{\"fileId\":\""+ fileId +"\"}";
6274                logger.debug(result);
6275               
6276                logger.debug("  {containerId:"+ fileId+"}");
6277                return Response.status(200).entity(result).build();
6278        }
6279       
6280       
6281         
6282}
Note: See TracBrowser for help on using the repository browser.