def call_BCCR(self): client = ClienteValidador( negocio=self.institution.bccr_bussiness, entidad=self.institution.bccr_entity, ) if client.validar_servicio('documento'): data = client.validar_documento(self.requestdata['document'], self.requestdata['format']) else: logger.warning("Validate document BCCR not available") data = client.DEFAULT_DOCUMENT_ERROR(self.get_default_error()) logger.debug("Validator BCCR: document %r" % (data, )) self.save_subject() self.adr.request_datetime = parse_datetime( self.requestdata['request_datetime']) self.adr.code = get_code_from_uuid(self.document_request.code) self.adr.status = data['codigo_error'] if 'texto_codigo_error' in data: self.adr.status_text = data['texto_codigo_error'] else: self.adr.status_text = get_text_representation( self.get_default_error(), data['codigo_error']) self.adr.was_successfully = data['exitosa'] self.adr.save() if data['exitosa']: self.get_warnings(data['advertencias']) self.get_found_errors(data['errores_encontrados']) self.get_signers(data['firmantes'])
def call_BCCR(self): client = ClienteValidador( negocio=self.institution.bccr_bussiness, entidad=self.institution.bccr_entity, ) if client.validar_servicio('certificado'): data = client.validar_certificado_autenticacion( self.requestdata['document']) data['code'] = get_code_from_uuid(self.cert_request.code) else: logger.warning("Validate certificate BCCR not available") data = client.DEFAULT_CERTIFICATE_ERROR data['code'] = 'N/D' logger.debug("Validator BCCR: certificate %r" % (data, )) self.save_subject() self.adr.request_datetime = parse_datetime( self.requestdata['request_datetime']) self.adr.code = data['code'] self.adr.status = data['codigo_error'] if 'texto_codigo_error' in data: self.adr.status_text = data['texto_codigo_error'] else: self.adr.status_text = get_text_representation( ERRORES_VALIDA_CERTIFICADO, data['codigo_error']) self.adr.was_successfully = data['exitosa'] if data['exitosa']: self.adr.identification = data['certificado']['identificacion'] self.adr.full_name = data['certificado']['nombre'] self.adr.start_validity = data['certificado']['inicio_vigencia'] self.adr.end_validity = data['certificado']['fin_vigencia']
def _extract_documento_xml(self, result, ERRORES_VALIDACION): dev = {} dev.update(self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDACION)) dev['codigo_error'] = 0 if result.FueExitosa else 1 dev['texto_codigo_error'] = get_text_representation( ERRORES_VALIDACION, dev['codigo_error']), dev['exitosa'] = result.FueExitosa dev['advertencias'] = None dev['errores_encontrados'] = None dev['firmantes'] = None if result.Advertencias: dev['advertencias'] = result.Advertencias.string if result.ErroresEncontrados: dev['errores_encontrados'] = [ (error.Codigo, error.Detalle) for error in result.ErroresEncontrados.ErrorDeDocumento ] if result.Firmantes: dev['firmantes'] = [{ 'identificacion': x.Cedula, 'fecha_firma': x.FechaDeFirma, 'nombre': x.NombreCompleto } for x in result.Firmantes.Firmante] return dev
def get_error_response(self, serializer): dev = { 'code': 'N/D', 'status': 2, 'status_text': get_text_representation(pyfva.constants.ERRORES_AL_SOLICITAR_FIRMA, 1), 'identification': 'N/D', 'id_transaction': 0, 'request_datetime': timezone.now(), 'sign_document': None, 'expiration_datetime': None, 'received_notification': False, 'error_info': serializer._errors } logger.debug('Sign: ERROR Institution %r' % (dev, )) return Response(self.get_encrypted_response(dev, serializer))
def call_BCCR(self): authclient = ClienteAutenticador(self.institution.bccr_bussiness, self.institution.bccr_entity) if authclient.validar_servicio(): data = authclient.solicitar_autenticacion( self.requestdata['identification']) else: logger.warning("Auth BCCR not available") data = authclient.DEFAULT_ERROR logger.debug("Authentication BCCR: %r" % (data, )) self.save_subject() self.adr.institution = self.institution self.adr.request_datetime = parse_datetime( self.requestdata['request_datetime']) self.adr.expiration_datetime = timezone.now( ) + timezone.timedelta(minutes=data['tiempo_maximo']) self.adr.duration = data['tiempo_maximo'] if 'texto_codigo_error' in data: self.adr.status_text = data['texto_codigo_error'] else: self.adr.status_text = get_text_representation( ERRORES_AL_SOLICITAR_FIRMA, data['codigo_error']) self.adr.status = data['codigo_error'] self.adr.id_transaction = data['id_solicitud'] self.adr.code = data['codigo_verificacion'] or 'N/D' self.adr.resume = data['resumen'] if 'resumen' in data else None
def _extract_solicitud_firma_completa(self, result): dev = {} dev.update(self.DEFAULT_ERROR) dev['codigo_error'] = result.CodigoDeError dev['texto_codigo_error'] = get_text_representation( ERRORES_VERIFICACION, result.CodigoDeError) dev['existe_firma'] = result.FueExitosa dev['fue_exitosa'] = result.ExisteUnaFirmaCompleta return dev
def DEFAULT_DOCUMENT_ERROR(self, ERRORES_VALIDA): return { 'exitosa': False, 'codigo_error': 1, 'texto_codigo_error': get_text_representation(ERRORES_VALIDA, 1), 'advertencias': None, 'errores_encontrados': None, 'firmantes': None, }
def get_error_response(self, serializer): dev = { "error_info": serializer._errors, 'code': 'N/D', 'status': 2, 'status_text': get_text_representation(self.DEFAULT_ERROR, 2), 'id_transaction': 0 } logger.debug('ViewSetBase Error %r' % (dev, )) return Response(self.get_encrypted_response(dev, serializer))
def _extrae_resultado(self, request, result): data = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation( ERRORES_AL_SOLICITAR_SELLO, result.CodigoDeError), 'fue_exitosa': result.FueExitosa, 'documento': result.DocumentoFirmado, 'hash_documento': result.HashDocumentoFirmado, 'id_algoritmo_hash': self.HASH_IDS[result.IDAlgoritmoHashDocumentoFirmado] } return data
def _extrae_resultado(self, request, result): data = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation(ERRORES_AL_SOLICITAR_FIRMA, result.CodigoDeError), 'codigo_verificacion': result.CodigoDeVerificacion, 'tiempo_maximo': result.TiempoMaximoDeFirmaEnSegundos, 'id_solicitud': result.IdDeLaSolicitud } return data
def reciba_notificacion(data): """ Recibe la notificación del BCCR :params data: Es un diccionario con los siguientes atributos * **id_solicitud:** Id de la solicitud del BCCR * **documento:** Documento firmado * **fue_exitosa:** si fue exitosa la firma * **codigo_error:** código de error * **hash_docfirmado:** Hash del documento ya firmado * **hash_id:** id del hash con que se genero el hash_docfirmado puede ser 1. Sha256, 2. Sha384 3. Sha512 No requiere retornar nada """ logdata = data if not settings.LOGGING_ENCRYPTED_DATA: logdata = {k: v for k, v in data.items() if k != 'documento'} logger.debug("Receptor: reciba notificación %r" % (logdata, )) for model in DATAREQUEST: request = model.objects.filter( id_transaction=data['id_solicitud']).first() if request is not None: break if request is None: logger.warning("Receptor: solicitud no encontrada %r" % (data, )) return logger.debug( str(type(request)) + " " + str(data['id_solicitud']) + " == " + str(request.status) + " --> " + str(data['codigo_error'])) request.status = data['codigo_error'] request.status_text = get_text_representation(ERRORES_AL_NOTIFICAR_FIRMA, data['codigo_error']) request.received_notification = True request.sign_document = get_document(data['documento']) request.hash_docsigned = get_hashsum_b64(data['hash_docfirmado']) request.hash_id_docsigned = data['hash_id'] request.save() if hasattr(request, 'institution'): if not request.institution.administrative_institution: send_notification(request, encrypt_method=get_encrypt_method(request))
def _extrae_resultado(self, request, result): data = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation(ERRORES_AL_SOLICITAR_FIRMA, result.CodigoDeError), 'codigo_verificacion': result.CodigoDeVerificacion, 'tiempo_maximo': result.TiempoMaximoDeFirmaEnSegundos, 'id_solicitud': result.IdDeLaSolicitud, 'resumen': result.ResumenDelDocumento } if result.InformacionSuscriptorDesconectado: data[ 'iniciado_en_firmador'] = result.InformacionSuscriptorDesconectado.HaIniciadoSesionEnElFirmador data[ 'ruta_descarga'] = result.InformacionSuscriptorDesconectado.RutaDeDescargaDelFirmador return data
def _extract_certificado_autenticacion(self, result): dev = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation(ERRORES_VALIDA_CERTIFICADO, result.CodigoDeError), 'exitosa': result.FueExitosa, 'certificado': None } if result.FueExitosa: cert = result.InformacionDelCertificado dev['certificado'] = { 'tipo_identificacion': cert.TipoDeIdentificacion, 'identificacion': cert.Identificacion or 'N/D', 'nombre': cert.NombreCompleto or 'N/D', 'inicio_vigencia': cert.FechaInicioDeLaVigencia, 'fin_vigencia': cert.FechaFinalDeLaVigencia } return dev
class ClienteVerificador(object): """Verifica si una firma ha sido completada .. note:: Los parámetros negocio y entidad de momento no son requeridos, pero puede que en un futuro cercano lo sean, por lo que se recomienda suministrarlos. :param negocio: número de identificación del negocio (provisto por el BCCR) :param entidad: número de identificación de la entidad (provisto por el BCCR) """ DEFAULT_ERROR = { 'codigo_error': 1, 'texto_codigo_error': get_text_representation(ERRORES_VERIFICACION, 1), 'existe_firma': False, 'fue_exitosa': False } def __init__(self, negocio=settings.DEFAULT_BUSSINESS, entidad=settings.DEFAULT_ENTITY): self.negocio = negocio self.entidad = entidad def existe_solicitud_de_firma_completa(self, identificacion): """Verifica si una solicitud de firma ha sida completada por el usuario en el sistema del BCCR :param identificacion: número de identificación de la persona Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_ERROR**. :returns: **codigo_error:** Número con el código de error 0 es éxito **texto_codigo_error:** Descripción del error **exitosa:** True si fue exitosa, False si no lo fue **existe_firma:** Retorna True si hay un proceso de firma activo o False si no. """ logger.info({ 'message': "Verificador: existe solicitud de firma completa", 'data': identificacion, 'location': __file__ }) try: dev = self._existe_solicitud_de_firma_completa(identificacion) except Exception as e: logger.error({ 'message': "Verificador: existe_solicitud_de_firma_completa", 'data': e, 'location': __file__ }) dev = self.DEFAULT_ERROR logger.debug({ 'message': "Verificador: existe solicitud de firma completa", 'data': { 'identification': identificacion, 'result': dev }, 'location': __file__ }) return dev def validar_servicio(self): """ Valida si el servicio está disponible. :returns: True si lo está o False si ocurrió algún error contactando al BCCR o el servicio no está disponible """ dev = self._validar_servicio() logger.debug({ 'message': "Verificador: validar servicio", 'data': dev, 'location': __file__ }) return dev # Private methods def _existe_solicitud_de_firma_completa(self, identificacion): stub = VerificadorSoapServiceStub() options = ExisteUnaSolicitudDeFirmaCompleta() options.laCedulaDelUsuario = identificacion status = stub.ExisteUnaSolicitudDeFirmaCompleta(options) result = status.soap_body.ExisteUnaSolicitudDeFirmaCompletaResult return self._extract_solicitud_firma_completa(result) def _extract_solicitud_firma_completa(self, result): dev = {} dev.update(self.DEFAULT_ERROR) dev['codigo_error'] = result.CodigoDeError dev['texto_codigo_error'] = get_text_representation( ERRORES_VERIFICACION, result.CodigoDeError) dev['existe_firma'] = result.FueExitosa dev['fue_exitosa'] = result.ExisteUnaFirmaCompleta return dev def _validar_servicio(self): stub = VerificadorSoapServiceStub() option = ValideElServicio() try: status = stub.ValideElServicio(option) dev = status.soap_body.ValideElServicioResult except Exception as e: logger.error({ 'message': "Verificador: Servicio de verificación fallando", 'data': e, 'location': __file__ }) dev = False return dev
class ClienteSellador(object): """Permite firmar con sello electrónico un documento utilizando los servicios del BCCR. Los documentos que se pueden firmar son: * XML: con cofirma y contrafirma * MSOffice: .docx, .xlsx y .pptx * ODF: .odt, .ods y .odp * PDF: .pdf .. note:: El número de entidad no se usa en sello electrónico :param negocio: número de identificación del negocio (provisto por el BCCR) :param entidad: número de identificación de la entidad (provisto por el BCCR) """ HASH_IDS = { 1: 'sha256', 2: 'sha384', 3: 'sha512' } DEFAULT_ERROR = { 'codigo_error': 1, 'texto_codigo_error': get_text_representation(ERRORES_AL_SOLICITAR_SELLO, 1), 'fue_exitosa': False, 'documento': None, 'hash_documento': None, 'id_algoritmo_hash': 'sha256' } def __init__(self, negocio=settings.DEFAULT_BUSSINESS, entidad=settings.DEFAULT_ENTITY): self.negocio = negocio self.entidad = entidad def get_now(self): return datetime.now() def firme(self, documento, formato, algoritmo_hash='Sha512', hash_doc=None, id_funcionalidad=-1, lugar=None, razon=None): """ Firma con sello electrónico cualquier documento enviado distinguiendo por el parámtetro formato cual método de firma llamar :param documento: Documento a firmar en base64 :param formato: Formato del documento, puede ser *xml_cofirma*, *xml_contrafirma*, *odf*, *msoffice*, *pdf* :param algoritmo_hash: Algoritmo utilizado para calcular el hash_doc, puede ser *sha256*, *sha384*, *sha512* :param hash_doc: hash del documento aplicando el algoritmo hash :param id_funcionalidad: Identificación de la funcionalidad del programa externo, se usa para dar seguimiento a la operación, * No obligatorio :param lugar: Lugar donde se realizó la firma (solo PDF) :param razon: Razon de firma para PDF (solo PDF) Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_ERROR**. :returns: **codigo_error:** Número con el código de error 1 es éxito **texto_codigo_error:** Descripción del error **fue_exitosa:** Verdadero si se pudo sellar, falso si hay un error **documento:** Documento en base64 si fue_exitosa True **hash_documento:** hash del documento en base64 si fue_exitosa True **id_algoritmo_hash:** algoritmo con el que se calculó la suma hash opciones: sha256, sha384, sha512 """ logger.info({'message': "Sellador: firme ", 'data': {'format': formato, 'hash_doc': hash_doc}, 'location': __file__}) logger.debug({'message': "Sellador: firme", 'data': repr(locals()), 'location': __file__}) algoritmo_hash = algoritmo_hash.title() if formato in ['xml_cofirma', 'xml_contrafirma']: _type = formato.replace('xml_', '') dev = self.firme_xml(documento, algoritmo_hash, hash_doc, id_funcionalidad, _type) elif formato == 'odf': dev = self.firme_odf(documento, algoritmo_hash, hash_doc, id_funcionalidad) elif formato == 'msoffice': dev = self.firme_msoffice(documento, algoritmo_hash, hash_doc, id_funcionalidad) elif formato == 'pdf': dev = self.firme_pdf(documento, algoritmo_hash=algoritmo_hash, hash_doc=hash_doc, id_funcionalidad=id_funcionalidad, lugar=lugar, razon=razon) else: logger.error({'message': "Formato de documento inválido", 'data': formato, 'location': __file__}) dev = self.DEFAULT_ERROR logger.debug({'message': "Sellador: firme result", 'data': dev, 'location': __file__}) return dev def firme_xml(self, documento, algoritmo_hash='Sha512', hash_doc=None, id_funcionalidad=-1, _type='cofirma'): """ Firma un documento XML, .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({'message': "Sellador: firme_xml", 'data': {'type': _type, 'hash_doc': hash_doc}, 'location': __file__}) logger.debug({'message': "Sellador: firme_xml", 'data': repr(locals()), 'location': __file__}) request = self._construya_solicitud(documento, algoritmo_hash, hash_doc, id_funcionalidad) try: dev = self._firme_xml(request, _type) except Exception as e: logger.error({'message': "Sellador: firmando en xml", 'data': {'type': _type, 'data': e}, 'location': __file__}) dev = self.DEFAULT_ERROR logger.debug({'message': "Sellador: firme_xml result", 'data': {'type': _type, 'data': dev}, 'location': __file__}) return dev def firme_odf(self, documento, algoritmo_hash='Sha512', hash_doc=None, id_funcionalidad=-1): """ Firma un documento del tipo ODF. .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({'message': "Sellador: firme_odf", 'data': {'hash_doc': hash_doc}, 'location': __file__}) logger.debug({'message': "Sellador: firme_odf", 'data': repr(locals()), 'location': __file__}) request = self._construya_solicitud(documento, algoritmo_hash, hash_doc, id_funcionalidad) try: dev = self._firme_odf(request) except Exception as e: logger.error({'message': "Sellador: firmando en odf", 'data': e, 'location': __file__}) dev = self.DEFAULT_ERROR logger.debug({'message': "Sellador: firme_odf result", 'data': dev, 'location': __file__}) return dev def firme_msoffice(self, documento, algoritmo_hash='Sha512', hash_doc=None, id_funcionalidad=-1): """ Firma un documento del tipo Microsoft office. .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({'message': "Sellador: firme_msoffice", 'data': {'hash_doc': hash_doc}, 'location': __file__}) logger.debug({'message': "Sellador: firme_msoffice", 'data': repr(locals()), 'location': __file__}) request = self._construya_solicitud(documento, algoritmo_hash, hash_doc, id_funcionalidad) try: dev = self._firme_msoffice(request) except Exception as e: logger.error({'message': "Sellador: firmando en msoffice", 'data': e, 'location': __file__}) dev = self.DEFAULT_ERROR logger.debug({'message': "Sellador: firme_msoffice result", 'data': dev, 'location': __file__}) return dev def firme_pdf(self, documento, algoritmo_hash='Sha512', hash_doc=None, id_funcionalidad=-1, lugar=None, razon=None): """ Firma un documento del tipo PDF. .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({'message': "Sellador: firme_pdf", 'data': {'hash_doc': hash_doc}, 'location': __file__}) logger.debug({'message': "Sellador: firme_pdf", 'data': repr(locals()), 'location': __file__}) request = self._construya_solicitud_pdf(documento, algoritmo_hash, hash_doc, id_funcionalidad, lugar, razon) try: dev = self._firme_pdf(request) except Exception as e: logger.error({'message': "Sellador: firmando en pdf", 'data': e, 'location': __file__}) dev = self.DEFAULT_ERROR logger.debug({'message': "Sellador: firme_pdf result", 'data': dev, 'location': __file__}) return dev def validar_servicio(self): """Verifica si el servicio está disponible :returns: True si el servicio está disponible, False si no lo está. """ dev = self._validar_servicio() logger.debug({'message': "Sellador: validar servicio", 'data': dev, 'location': __file__}) return dev def extrae_resultado(self, solicitud, resultado): """Convierte la infromación obtenida del servicio SOAP a python :param solicitud: Objeto de solicitud del tipo *pyfva.soap.firmador.SolicitudDeFirma* :param resultado: Objeto de respuesta del tipo *pyfva.soap.firmador.RecibaLaSolicitudDeSelladoElectronicoXmlEnvelopedCoFirmaResult* Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_ERROR**. :returns: **codigo_error:** Número con el código de error 1 es éxito **texto_codigo_error:** Descripción del error **fue_exitosa:** Verdadero si se pudo sellar, falso si hay un error **documento:** Documento en base64 si fue_exitosa True **hash_documento:** hash del documento en base64 si fue_exitosa True **id_algoritmo_hash:** algoritmo con el que se calculó la suma hash opciones: sha256, sha384, sha512 """ try: data = self._extrae_resultado(solicitud, resultado) except Exception as e: logger.error({'message': "Sellador: extrayendo resultados %r", 'data': e, 'location': __file__}) data = self.DEFAULT_ERROR return data def _construya_solicitud(self, documento, algoritmo_hash='Sha512', hash_doc=None, id_funcionalidad=-1): request = SolicitudDeFirma.create(self.get_now(), algoritmo_hash, self.negocio, id_funcionalidad) request.Documento = documento request.HashDocumento = hash_doc request.IdFuncionalidad = id_funcionalidad return request def _construya_solicitud_pdf(self, documento, algoritmo_hash='Sha512', hash_doc=None, id_funcionalidad=-1, lugar=None, razon=None): request = SolicitudDeFirmaPdf.create( self.negocio, self.get_now(), algoritmo_hash, id_funcionalidad ) request.Documento = documento request.HashDocumento = hash_doc if lugar: request.Lugar = lugar if razon: request.RazonDeFirma = razon return request # Private methods def _extrae_resultado(self, request, result): data = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation( ERRORES_AL_SOLICITAR_SELLO, result.CodigoDeError), 'fue_exitosa': result.FueExitosa, 'documento': result.DocumentoFirmado, 'hash_documento': result.HashDocumentoFirmado, 'id_algoritmo_hash': self.HASH_IDS[result.IDAlgoritmoHashDocumentoFirmado] } return data def _firme_xml(self, request, _type): stub = SelladorElectronicoConControlDeLlaveSoapServiceStub() if _type == 'cofirma': options = RecibaLaSolicitudDeSelladoElectronicoXmlEnvelopedCoFirma() options.laSolicitud = request status = stub.RecibaLaSolicitudDeSelladoElectronicoXmlEnvelopedCoFirma(options) return self.extrae_resultado(request, status.soap_body.RecibaLaSolicitudDeSelladoElectronicoXmlEnvelopedCoFirmaResult) elif _type == 'contrafirma': options = RecibaLaSolicitudDeSelladoElectronicoXmlEnvelopedContraFirma() options.laSolicitud = request status = stub.RecibaLaSolicitudDeSelladoElectronicoXmlEnvelopedContraFirma( options) return self.extrae_resultado(request, status.soap_body.RecibaLaSolicitudDeSelladoElectronicoXmlEnvelopedContraFirmaResult) def _firme_odf(self, request): stub = SelladorElectronicoConControlDeLlaveSoapServiceStub() options = RecibaLaSolicitudDeSelladoElectronicoOdf() options.laSolicitud = request status = stub.RecibaLaSolicitudDeSelladoElectronicoOdf(options) return self.extrae_resultado(request, status.soap_body.RecibaLaSolicitudDeSelladoElectronicoOdfResult) def _firme_msoffice(self, request): stub = SelladorElectronicoConControlDeLlaveSoapServiceStub() options = RecibaLaSolicitudDeSelladoElectronicoMSOffice() options.laSolicitud = request status = stub.RecibaLaSolicitudDeSelladoElectronicoMSOffice(options) return self.extrae_resultado(request, status.soap_body.RecibaLaSolicitudDeSelladoElectronicoMSOfficeResult) def _firme_pdf(self, request): stub = SelladorElectronicoConControlDeLlaveSoapServiceStub() options = RecibaLaSolicitudDeSelladoElectronicoPdf() options.laSolicitud = request status = stub.RecibaLaSolicitudDeSelladoElectronicoPdf(options) return self.extrae_resultado(request, status.soap_body.RecibaLaSolicitudDeSelladoElectronicoPdfResult) def _validar_servicio(self): stub = SelladorElectronicoConControlDeLlaveSoapServiceStub() option = ElServicioEstaDisponible() try: status = stub.ElServicioEstaDisponible(option) dev = status.soap_body.ElServicioEstaDisponibleResult except Exception as e: logger.error({'message': "Sellador: Servicio de firmado fallando", 'data': e, 'location': __file__}) dev = False return dev
class ClienteValidador(object): """Permite validar una firma o un documento utilizando los servicios del BCCR Los documentos que se pueden validar son: * Certificados digitales (CA nacional) * XML: con cofirma y contrafirma * MSOffice: .docx, .xlsx y .pptx * ODF: .odt, .ods y .odp * PDF: .pdf .. note:: Los parámetros negocio y entidad de momento no son requeridos, pero puede que en un futuro cercano lo sean, por lo que se recomienda suministrarlos. :param negocio: número de identificación del negocio (provisto por el BCCR) :param entidad: número de identificación de la entidad (provisto por el BCCR) """ DEFAULT_CERTIFICATE_ERROR = { 'codigo_error': 1, 'texto_codigo_error': get_text_representation(ERRORES_VALIDA_CERTIFICADO, 1), 'exitosa': False, 'certificado': None } def DEFAULT_DOCUMENT_ERROR(self, ERRORES_VALIDA): return { 'exitosa': False, 'codigo_error': 1, 'texto_codigo_error': get_text_representation(ERRORES_VALIDA, 1), 'advertencias': None, 'errores_encontrados': None, 'firmantes': None, } def __init__(self, negocio=settings.DEFAULT_BUSSINESS, entidad=settings.DEFAULT_ENTITY): self.negocio = negocio self.entidad = entidad def validar_documento(self, documento, formato): """Valida si el documento está firmado correctamente. :param documento: documento xml en base64 :param formato: tipo de documento a validar (cofirma, contrafirma, msoffice, odf). Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_DOCUMENT_ERROR**. .. note:: Observe que en caso de no ser exitosa la operación los atributos 'advertencias', 'errores_encontrados' y 'firmantes' retornarán None :returns: **codigo_error:** Número con el código de error 0 es éxito **texto_codigo_error:** Descripción del error **exitosa:** True si fue exitoso el verificado del documento, False si no lo fue **advertencias:** Lista de advertencias encontradas durante el proceso de validadación, algo como: ["adv1", "adv2"] **errores_encontrados:** Lista de errores encontrados y su respectivo detalle, ej [("código de error", "Detalle del error"), ...] **firmantes:** Lista de información del los firmantes, ej [ {'identificacion': "8-0888-0888", 'fecha_firma': datetime.now(), 'nombre': "Juanito Mora Porras"}, ... ] """ logger.debug({ 'message': "Validador: validar_documento", 'data': { 'format': formato, 'data': repr(locals()) }, 'location': __file__ }) try: if formato == 'cofirma': dev = self._validar_documento_cofirma(documento) elif formato == 'contrafirma': dev = self._validar_documento_contrafirma(documento) elif formato == 'msoffice': dev = self._validar_documento_msoffice(documento) elif formato == 'odf': dev = self._validar_documento_odf(documento) elif formato == 'pdf': dev = self._validar_documento_pdf(documento) else: logger.error({ 'message': "Validador: validando documento", 'data': { 'format': formato, 'message': "No existe formato especificado" }, 'location': __file__ }) dev = self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDAR_XMLCOFIRMA) except Exception as e: logger.error({ 'message': "Validador: validando documento", 'data': { 'format': formato, 'message': e }, 'location': __file__ }) dev = self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDAR_XMLCOFIRMA) logger.info({ 'message': "Validador: validar_documento", 'data': { 'format': formato, 'result': dev }, 'location': __file__ }) return dev def validar_certificado_autenticacion(self, certificado): """Valida si el certificado de autenticación es válido y no está revocado. :param certificado: Certificado en base64 Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_CERTIFICATE_ERROR**. :returns: **codigo_error:** Número con el código de error 0 es éxito **texto_codigo_error:** Descripción del error **exitosa:** True si fue exitosa, False si no lo fue **certificado:** Si la operación no fue exitosa retorna None, si lo fue retorna un diccionario con: **identificacion:** Número de identificación del suscriptor dueño del certificado **nombre:** Nombre completo del suscriptor dueño del certificado **inicio_vigencia:** Fecha de inicio del vigencia del certificado **fin_vigencia:** Fecha de finalización de la vigencia del certificado """ logger.debug({ 'message': "Validador: validar_certificado_autenticacion", 'data': repr(locals()), 'location': __file__ }) try: dev = self._validar_certificado_autenticacion(certificado) except Exception as e: logger.error({ 'message': "Validador: validando certificado", 'data': e, 'location': __file__ }) dev = self.DEFAULT_CERTIFICATE_ERROR logger.info({ 'message': "Validador: validar_certificado_autenticacion result ", 'data': dev, 'location': __file__ }) return dev def validar_servicio(self, servicio): """Valida si el servicio está disponible. :param servicio: tipo de servicio a validar, puede ser 'certificado' o 'documento' :returns: True si lo está o False si ocurrió algún error contactando al BCCR o el servicio no está disponible """ dev = False if servicio.lower() == 'certificado': dev = self._validar_servicio_certificado() elif servicio.lower() == 'documento': dev = self._validar_servicio_documento() logger.info({ 'message': "Validador: Validar servicio", 'data': { 'servicio': servicio, 'result': dev }, 'location': __file__ }) return dev # Private methods def _validar_documento_cofirma(self, documento): stub = ValidadorDeDocumentoSoapServiceStub() options = ValideElDocumentoXmlEnvelopedCoFirma() options.elDocumentoXml = documento try: status = stub.ValideElDocumentoXmlEnvelopedCoFirma(options) dev = self._extract_documento_xml( status.soap_body.ValideElDocumentoXmlEnvelopedCoFirmaResult, ERRORES_VALIDAR_XMLCOFIRMA) except Exception as e: logger.error({ 'message': "Validador: validando cofirma", 'data': e, 'location': __file__ }) dev = self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDAR_XMLCOFIRMA) return dev def _validar_documento_contrafirma(self, documento): stub = ValidadorDeDocumentoSoapServiceStub() options = ValideElDocumentoXmlEnvelopedContraFirma() options.elDocumentoXml = documento try: status = stub.ValideElDocumentoXmlEnvelopedContraFirma(options) dev = self._extract_documento_xml( status.soap_body. ValideElDocumentoXmlEnvelopedContraFirmaResult, ERRORES_VALIDAR_XMLCONTRAFIRMA) except Exception as e: traceback.print_exc() logger.error({ 'message': "Validador: validando contrafirma", 'data': e, 'location': __file__ }) dev = self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDAR_XMLCONTRAFIRMA) return dev def _validar_documento_msoffice(self, documento): stub = ValidadorDeDocumentoSoapServiceStub() options = ValideElDocumentoMSOffice() options.elDocumentoOffice = documento try: status = stub.ValideElDocumentoMSOffice(options) dev = self._extract_documento_xml( status.soap_body.ValideElDocumentoMSOfficeResult, ERRORES_VALIDAR_MSOFFICE) except Exception as e: logger.error({ 'message': "Validador: validando MSOffice", 'data': e, 'location': __file__ }) dev = self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDAR_MSOFFICE) return dev def _validar_documento_odf(self, documento): stub = ValidadorDeDocumentoSoapServiceStub() options = ValideElDocumentoOdf() options.elDocumentoOdf = documento try: status = stub.ValideElDocumentoOdf(options) dev = self._extract_documento_xml( status.soap_body.ValideElDocumentoOdfResult, ERRORES_VALIDAR_ODF) except Exception as e: logger.error({ 'message': "Validador: validando ODF", 'data': e, 'location': __file__ }) dev = self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDAR_ODF) return dev def _validar_documento_pdf(self, documento): stub = ValidadorDeDocumentoSoapServiceStub() options = ValideElDocumentoPdf() options.elDocumentoPdf = documento try: status = stub.ValideElDocumentoPdf(options) dev = self._extract_documento_xml( status.soap_body.ValideElDocumentoPdfResult, ERRORES_VALIDAR_PDF) except Exception as e: logger.error({ 'message': "Validador: validando PDF", 'data': e, 'location': __file__ }) dev = self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDAR_PDF) return dev def _extract_documento_xml(self, result, ERRORES_VALIDACION): dev = {} dev.update(self.DEFAULT_DOCUMENT_ERROR(ERRORES_VALIDACION)) dev['codigo_error'] = 0 if result.FueExitosa else 1 dev['texto_codigo_error'] = get_text_representation( ERRORES_VALIDACION, dev['codigo_error']), dev['exitosa'] = result.FueExitosa dev['advertencias'] = None dev['errores_encontrados'] = None dev['firmantes'] = None if result.Advertencias: dev['advertencias'] = result.Advertencias.string if result.ErroresEncontrados: dev['errores_encontrados'] = [ (error.Codigo, error.Detalle) for error in result.ErroresEncontrados.ErrorDeDocumento ] if result.Firmantes: dev['firmantes'] = [{ 'identificacion': x.Cedula, 'fecha_firma': x.FechaDeFirma, 'nombre': x.NombreCompleto } for x in result.Firmantes.Firmante] return dev def _validar_certificado_autenticacion(self, certificado): stub = ValidadorDeCertificadoSoapServiceStub() options = SoliciteLaValidacionDelCertificadoDeAutenticacion() options.elCertificadoDeAutenticacion = certificado status = stub.SoliciteLaValidacionDelCertificadoDeAutenticacion( options) result = status.soap_body.SoliciteLaValidacionDelCertificadoDeAutenticacionResult return self._extract_certificado_autenticacion(result) def _extract_certificado_autenticacion(self, result): dev = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation(ERRORES_VALIDA_CERTIFICADO, result.CodigoDeError), 'exitosa': result.FueExitosa, 'certificado': None } if result.FueExitosa: cert = result.InformacionDelCertificado dev['certificado'] = { 'tipo_identificacion': cert.TipoDeIdentificacion, 'identificacion': cert.Identificacion or 'N/D', 'nombre': cert.NombreCompleto or 'N/D', 'inicio_vigencia': cert.FechaInicioDeLaVigencia, 'fin_vigencia': cert.FechaFinalDeLaVigencia } return dev def _validar_servicio_certificado(self): stub = ValidadorDeCertificadoSoapServiceStub() option = ValideServicioCertificado() try: status = stub.ValideElServicio(option) dev = status.soap_body.ValideElServicioResult except Exception as e: logger.error({ 'message': "Validador: Servicio de validado de certificado fallando", 'data': e, 'location': __file__ }) dev = False return dev def _validar_servicio_documento(self): stub = ValidadorDeDocumentoSoapServiceStub() option = ValideServicioDocumento() try: status = stub.ValideElServicio(option) dev = status.soap_body.ValideElServicioResult except Exception as e: logger.error({ 'message': "Validador: Servicio de validado de documentos fallando", 'data': e, 'location': __file__ }) dev = False return dev
class ClienteFirmador(object): """Permite firmar un documento utilizando los servicios del BCCR. Los documentos que se pueden firmar son: * XML: con cofirma y contrafirma * MSOffice: .docx, .xlsx y .pptx * ODF: .odt, .ods y .odp * PDF: .pdf .. note:: Recuerde la política del banco es *no nos llame, nosotros lo llamamos* :param negocio: número de identificación del negocio (provisto por el BCCR) :param entidad: número de identificación de la entidad (provisto por el BCCR) """ DEFAULT_ERROR = { 'codigo_error': 1, 'texto_codigo_error': get_text_representation(ERRORES_AL_SOLICITAR_FIRMA, 1), 'codigo_verificacion': 'N/D', 'tiempo_maximo': 1, 'id_solicitud': 0 } def __init__(self, negocio=settings.DEFAULT_BUSSINESS, entidad=settings.DEFAULT_ENTITY): self.negocio = negocio self.entidad = entidad def get_now(self): return datetime.now() def firme(self, identidad, documento, formato, algoritmo_hash='Sha512', hash_doc=None, resumen='', id_funcionalidad=-1, lugar=None, razon=None): """ Firma cualquier documento enviado distinguiendo por el parámtetro formato cual método de firma llamar :param identidad: Identidad del suscriptor a firmar :param documento: Documento a firmar en base64 :param formato: Formato del documento, puede ser *xml_cofirma*, *xml_contrafirma*, *odf*, *msoffice*, *pdf* :param algoritmo_hash: Algoritmo utilizado para calcular el hash_doc, puede ser *sha256*, *sha384*, *sha512* :param hash_doc: hash del documento aplicando el algoritmo hash :param resumen: Información resumida para mostar al suscriptor que describe el documento :param id_funcionalidad: Identificación de la funcionalidad del programa externo, se usa para dar seguimiento a la operación, * No obligatorio :param lugar: Lugar donde se realizó la firma (solo PDF) :param razon: Razon de firma para PDF (solo PDF) Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_ERROR**. :returns: **codigo_error:** Número con el código de error 1 es éxito **texto_codigo_error:** Descripción del error **codigo_verificacion:** str con el código de verificación de la trasacción, se muestra al usuario **tiempo_maximo:** Tiempo máximo de duración de la solicitud en segundos **id_solicitud:** Número de identificación de la solicitud """ logger.info({ 'message': "Firmador: firme ", 'data': { 'identity': identidad, 'format': formato, 'hash_doc': hash_doc }, 'location': __file__ }) logger.debug({ 'message': "Firmador: firme", 'data': repr(locals()), 'location': __file__ }) algoritmo_hash = algoritmo_hash.title() if formato in ['xml_cofirma', 'xml_contrafirma']: _type = formato.replace('xml_', '') dev = self.firme_xml(identidad, documento, algoritmo_hash, hash_doc, resumen, id_funcionalidad, _type) elif formato == 'odf': dev = self.firme_odf(identidad, documento, algoritmo_hash, hash_doc, resumen, id_funcionalidad) elif formato == 'msoffice': dev = self.firme_msoffice(identidad, documento, algoritmo_hash, hash_doc, resumen, id_funcionalidad) elif formato == 'pdf': dev = self.firme_pdf(identidad, documento, algoritmo_hash=algoritmo_hash, hash_doc=hash_doc, resumen=resumen, id_funcionalidad=id_funcionalidad, lugar=lugar, razon=razon) else: logger.error({ 'message': "Formato de documento inválido", 'data': formato, 'location': __file__ }) dev = self.DEFAULT_ERROR logger.debug({ 'message': "Firmador: firme result", 'data': dev, 'location': __file__ }) return dev def firme_xml(self, identidad, documento, algoritmo_hash='Sha512', hash_doc=None, resumen='', id_funcionalidad=-1, _type='cofirma'): """ Firma un documento XML, .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({ 'message': "Firmador: firme_xml", 'data': { 'type': _type, 'identity': identidad, 'hash_doc': hash_doc }, 'location': __file__ }) logger.debug({ 'message': "Firmador: firme_xml", 'data': repr(locals()), 'location': __file__ }) request = self._construya_solicitud(identidad, documento, algoritmo_hash, hash_doc, resumen, id_funcionalidad) try: dev = self._firme_xml(request, _type) except Exception as e: logger.error({ 'message': "Firmador: firmando en xml", 'data': { 'type': _type, 'data': e }, 'location': __file__ }) dev = self.DEFAULT_ERROR logger.debug({ 'message': "Firmador: firme_xml result", 'data': { 'type': _type, 'data': dev }, 'location': __file__ }) return dev def firme_odf(self, identidad, documento, algoritmo_hash='Sha512', hash_doc=None, resumen='', id_funcionalidad=-1): """ Firma un documento del tipo ODF. .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({ 'message': "Firmador: firme_odf", 'data': { 'identity': identidad, 'hash_doc': hash_doc }, 'location': __file__ }) logger.debug({ 'message': "Firmador: firme_odf", 'data': repr(locals()), 'location': __file__ }) request = self._construya_solicitud(identidad, documento, algoritmo_hash, hash_doc, resumen, id_funcionalidad) try: dev = self._firme_odf(request) except Exception as e: logger.error({ 'message': "Firmador: firmando en odf", 'data': e, 'location': __file__ }) dev = self.DEFAULT_ERROR logger.debug({ 'message': "Firmador: firme_odf result", 'data': dev, 'location': __file__ }) return dev def firme_msoffice(self, identidad, documento, algoritmo_hash='Sha512', hash_doc=None, resumen='', id_funcionalidad=-1): """ Firma un documento del tipo Microsoft office. .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({ 'message': "Firmador: firme_msoffice", 'data': { 'identity': identidad, 'hash_doc': hash_doc }, 'location': __file__ }) logger.debug({ 'message': "Firmador: firme_msoffice", 'data': repr(locals()), 'location': __file__ }) request = self._construya_solicitud(identidad, documento, algoritmo_hash, hash_doc, resumen, id_funcionalidad) try: dev = self._firme_msoffice(request) except Exception as e: logger.error({ 'message': "Firmador: firmando en msoffice", 'data': e, 'location': __file__ }) dev = self.DEFAULT_ERROR logger.debug({ 'message': "Firmador: firme_msoffice result", 'data': dev, 'location': __file__ }) return dev def firme_pdf(self, identidad, documento, algoritmo_hash='Sha512', hash_doc=None, resumen='', id_funcionalidad=-1, lugar=None, razon=None): """ Firma un documento del tipo PDF. .. note:: Los parámetros exceptuando formato (no existe en este método) son idénticos que los de firme, además los resultados retornados son también idénticos. """ logger.info({ 'message': "Firmador: firme_pdf", 'data': { 'identity': identidad, 'hash_doc': hash_doc }, 'location': __file__ }) logger.debug({ 'message': "Firmador: firme_pdf", 'data': repr(locals()), 'location': __file__ }) request = self._construya_solicitud_pdf(identidad, documento, algoritmo_hash, hash_doc, resumen, id_funcionalidad, lugar, razon) try: dev = self._firme_pdf(request) except Exception as e: logger.error({ 'message': "Firmador: firmando en pdf", 'data': e, 'location': __file__ }) dev = self.DEFAULT_ERROR logger.debug({ 'message': "Firmador: firme_pdf result", 'data': dev, 'location': __file__ }) return dev def suscriptor_conectado(self, identificacion): """Verifica si un suscriptor está conectado. :param identificacion: Identificación del suscriptor :returns: True si la tarjeta del suscriptor está conectada, False si no lo está. """ dev = self._suscriptor_conectado(identificacion) logger.debug({ 'message': "Firmador: suscriptor conectado", 'data': dev, 'location': __file__ }) return dev def validar_servicio(self): """Verifica si el servicio está disponible :returns: True si el servicio está disponible, False si no lo está. """ dev = self._validar_servicio() logger.debug({ 'message': "Firmador: validar servicio", 'data': dev, 'location': __file__ }) return dev def extrae_resultado(self, solicitud, resultado): """Convierte la infromación obtenida del servicio SOAP a python :param solicitud: Objeto de solicitud del tipo *pyfva.soap.firmador.SolicitudDeFirma* :param resultado: Objeto de respuesta del tipo *pyfva.soap.firmador.RecibaLaSolicitudDeFirmaXmlEnvelopedCoFirmaResult* Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_ERROR**. :returns: **codigo_error:** Número con el código de error 0 es éxito **texto_codigo_error:** Descripción del error **codigo_verificacion:** str con el código de verificación de la trasacción **tiempo_maximo:** Tiempo máximo de duración de la solicitud en segundos **id_solicitud:** Número de identificación de la solicitud """ try: data = self._extrae_resultado(solicitud, resultado) except Exception as e: logger.error({ 'message': "Firmador: extrayendo resultados %r", 'data': e, 'location': __file__ }) data = self.DEFAULT_ERROR return data def _construya_solicitud(self, identidad, documento, algoritmo_hash='Sha512', hash_doc=None, resumen='', id_funcionalidad=-1): request = SolicitudDeFirma.create(self.negocio, self.get_now(), algoritmo_hash, id_funcionalidad, self.entidad) request.Documento = documento request.HashDocumento = hash_doc request.IdentificacionDelSuscriptor = identidad request.IdFuncionalidad = id_funcionalidad request.ResumenDocumento = resumen return request def _construya_solicitud_pdf(self, identidad, documento, algoritmo_hash='Sha512', hash_doc=None, resumen='', id_funcionalidad=-1, lugar=None, razon=None): request = SolicitudDeFirmaPdf.create(self.negocio, self.get_now(), algoritmo_hash, id_funcionalidad, self.entidad) request.Documento = documento request.HashDocumento = hash_doc request.IdentificacionDelSuscriptor = identidad request.IdFuncionalidad = id_funcionalidad request.ResumenDocumento = resumen if lugar: request.Lugar = lugar if razon: request.RazonDeFirma = razon return request # Private methods def _extrae_resultado(self, request, result): data = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation(ERRORES_AL_SOLICITAR_FIRMA, result.CodigoDeError), 'codigo_verificacion': result.CodigoDeVerificacion, 'tiempo_maximo': result.TiempoMaximoDeFirmaEnSegundos, 'id_solicitud': result.IdDeLaSolicitud } return data def _firme_xml(self, request, _type): stub = FirmadorSoapServiceStub() if _type == 'cofirma': options = RecibaLaSolicitudDeFirmaXmlEnvelopedCoFirma() options.laSolicitud = request status = stub.RecibaLaSolicitudDeFirmaXmlEnvelopedCoFirma(options) return self.extrae_resultado( request, status.soap_body. RecibaLaSolicitudDeFirmaXmlEnvelopedCoFirmaResult) elif _type == 'contrafirma': options = RecibaLaSolicitudDeFirmaXmlEnvelopedContraFirma() options.laSolicitud = request status = stub.RecibaLaSolicitudDeFirmaXmlEnvelopedContraFirma( options) return self.extrae_resultado( request, status.soap_body. RecibaLaSolicitudDeFirmaXmlEnvelopedContraFirmaResult) def _firme_odf(self, request): stub = FirmadorSoapServiceStub() options = RecibaLaSolicitudDeFirmaODF() options.laSolicitud = request status = stub.RecibaLaSolicitudDeFirmaODF(options) return self.extrae_resultado( request, status.soap_body.RecibaLaSolicitudDeFirmaODFResult) def _firme_msoffice(self, request): stub = FirmadorSoapServiceStub() options = RecibaLaSolicitudDeFirmaMSOffice() options.laSolicitud = request status = stub.RecibaLaSolicitudDeFirmaMSOffice(options) return self.extrae_resultado( request, status.soap_body.RecibaLaSolicitudDeFirmaMSOfficeResult) def _firme_pdf(self, request): stub = FirmadorSoapServiceStub() options = RecibaLaSolicitudDeFirmaPdf() options.laSolicitud = request status = stub.RecibaLaSolicitudDeFirmaPdf(options) return self.extrae_resultado( request, status.soap_body.RecibaLaSolicitudDeFirmaPdfResult) def _suscriptor_conectado(self, identificacion): stub = FirmadorSoapServiceStub() options = ElSuscriptorEstaConectado() options.laIdentificacion = identificacion try: status = stub.ElSuscriptorEstaConectado(options) dev = status.soap_body.ElSuscriptorEstaConectadoResult except Exception as e: logger.error({ 'message': "Firmador: Servicio de firmado fallando en usuario conectado", 'data': e, 'location': __file__ }) dev = False return dev def _validar_servicio(self): stub = FirmadorSoapServiceStub() option = ValideElServicio() try: status = stub.ValideElServicio(option) dev = status.soap_body.ValideElServicioResult except Exception as e: logger.error({ 'message': "Firmador: Servicio de firmado fallando", 'data': e, 'location': __file__ }) dev = False return dev
class ClienteAutenticador(object): """Permite autenticar una persona utilizando los servicios del BCCR .. note:: Recuerde la política del banco es *no nos llame, nosotros lo llamamos* :param negocio: número de identificación del negocio (provisto por el BCCR) :param entidad: número de identificación de la entidad (provisto por el BCCR) """ DEFAULT_ERROR = { 'codigo_error': 1, 'texto_codigo_error': get_text_representation(ERRORES_AL_SOLICITAR_FIRMA, 1), 'codigo_verificacion': 'N/D', 'tiempo_maximo': 1, 'id_solicitud': 0 } def __init__(self, negocio=settings.DEFAULT_BUSSINESS, entidad=settings.DEFAULT_ENTITY): self.negocio = negocio self.entidad = entidad def get_now(self): return datetime.now() def solicitar_autenticacion(self, identificacion, id_funcionalidad=-1): """Solicita al BCCR la autenticación de la identificacion, recuerde, la política del BCCR es: *no nos llame, nosotros lo llamamos*, por lo que los valores devueltos corresponden al estado de la petición y no al resultado de la firma :param identificacion: número de identificación de la persona ver `Formato identificacion <formatos.html#formato-de-identificacion>`_. :param id_funcionalidad: Identificación de la funcionalidad del programa externo, se usa para dar seguimiento a la operación, * No obligatorio Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_ERROR**. :returns: **codigo_error:** Número con el código de error 0 es éxito **texto_codigo_error:** Descripción del error **codigo_verificacion:** str con el código de verificación de la trasacción, se muestra al usuario **tiempo_maximo:** Tiempo máximo de duración de la solicitud en segundos **id_solicitud:** Número de identificación de la solicitud """ logger.info({ 'message': "Autenticador: Solicitar_autenticacion", 'data': identificacion, 'location': __file__ }) request = SolicitudDeAutenticacion.create(self.negocio, self.get_now(), id_funcionalidad, self.entidad, identificacion) logger.debug({ 'message': "Autenticador: Solicitar_autenticacion Fin", 'data': { 'negocio': self.negocio, 'hora': self.get_now().isoformat(), 'entidad': self.entidad, 'identificacion': identificacion }, 'location': __file__ }) try: dev = self._solicitar_autenticacion(request) except: dev = self.DEFAULT_ERROR logger.debug({ "message": "Autenticador: Solicitar_autenticacion", 'data': dev, 'location': __file__ }) return dev def validar_servicio(self): """ Valida si el servicio está disponible. :returns: True si lo está o False si ocurrió algún error contactando al BCCR o el servicio no está disponible """ dev = self._validar_servicio() logger.debug({ 'message': "Autenticador: validar_servicio", 'data': dev, 'location': __file__ }) return dev def extrae_resultado(self, solicitud, resultado): """Convierte la infromación obtenida del servicio SOAP a python :param solicitud: Objeto de solicitud del tipo *pyfva.soap.autenticador.SolicitudDeAutenticacion* :param resultado: Objeto de respuesta del tipo *pyfva.soap.autenticador.RecibaLaSolicitudDeAutenticacionResult* Retorna una diccionario con los siguientes elementos, en caso de error retorna **DEFAULT_ERROR**. :returns: **codigo_error:** Número con el código de error 0 es éxito **texto_codigo_error:** Descripción del error **codigo_verificacion:** str con el código de verificación de la trasacción **tiempo_maximo:** Tiempo máximo de duración de la solicitud en segundos **id_solicitud:** Número de identificación de la solicitud """ try: data = self._extrae_resultado(solicitud, resultado) except Exception as e: logger.error({ 'message': 'Autenticador: extrayendo datos', 'data': e, 'location': __file__ }) data = self.DEFAULT_ERROR return data def _solicitar_autenticacion(self, request): stub = AutenticadorSoapServiceStub() options = RecibaLaSolicitudDeAutenticacion() options.laSolicitud = request status = stub.RecibaLaSolicitudDeAutenticacion(options) return self.extrae_resultado( request, status.soap_body.RecibaLaSolicitudDeAutenticacionResult) def _extrae_resultado(self, request, result): data = { 'codigo_error': result.CodigoDeError, 'texto_codigo_error': get_text_representation(ERRORES_AL_SOLICITAR_FIRMA, result.CodigoDeError), 'codigo_verificacion': result.CodigoDeVerificacion, 'tiempo_maximo': result.TiempoMaximoDeFirmaEnSegundos, 'id_solicitud': result.IdDeLaSolicitud, 'resumen': result.ResumenDelDocumento } if result.InformacionSuscriptorDesconectado: data[ 'iniciado_en_firmador'] = result.InformacionSuscriptorDesconectado.HaIniciadoSesionEnElFirmador data[ 'ruta_descarga'] = result.InformacionSuscriptorDesconectado.RutaDeDescargaDelFirmador return data def _validar_servicio(self): stub = AutenticadorSoapServiceStub() option = ValideElServicio() try: status = stub.ValideElServicio(option) dev = status.soap_body.ValideElServicioResult except Exception as e: logger.error({ 'message': "Autenticador: servicio validar autenticacion fallando", 'data': e, 'location': __file__ }) dev = False return dev