Ejemplo n.º 1
0
    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'])
Ejemplo n.º 2
0
    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']
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
 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))
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
 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
Ejemplo n.º 7
0
 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,
     }
Ejemplo n.º 8
0
 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))
Ejemplo n.º 9
0
    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
Ejemplo n.º 10
0
 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
Ejemplo n.º 11
0
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))
Ejemplo n.º 12
0
 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
Ejemplo n.º 13
0
    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
Ejemplo n.º 14
0
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
Ejemplo n.º 15
0
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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
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
Ejemplo n.º 18
0
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