예제 #1
0
파일: as2lib.py 프로젝트: VDuda/pyas2
def save_mdn(message, mdn_content):
    """ Process the received MDN and check status of sent message. Takes the raw mdn as input, verifies the signature
    if present and the extracts the status of the original message."""

    try:
        # Parse the raw mdn to an email.Message
        mdn_message = email.message_from_string(mdn_content)
        mdn_headers = ''
        for key in mdn_message.keys():
            mdn_headers += '%s: %s\n' % (key, mdn_message[key])
        message_id = mdn_message.get('message-id')

        # Raise error if message is not an MDN
        if mdn_message.get_content_type() not in [
                'multipart/signed', 'multipart/report'
        ]:
            raise as2utils.As2Exception(
                _(u'MDN report not found in the response'))

        # Raise error if signed MDN requested and unsigned MDN returned
        if message.partner.mdn_sign and mdn_message.get_content_type(
        ) != 'multipart/signed':
            models.Log.objects.create(
                message=message,
                status='W',
                text=_(u'Expected signed MDN but unsigned MDN returned'))

        mdn_signed = False
        if mdn_message.get_content_type() == 'multipart/signed':
            # Verify the signature in the MDN message
            models.Log.objects.create(
                message=message,
                status='S',
                text=_(
                    u'Verifying the signed MDN with partner key {0:s}'.format(
                        message.partner.signature_key)))
            mdn_signed = True

            # Get the partners public and ca certificates
            cert = str(message.partner.signature_key.certificate.path)
            ca_cert = cert
            if message.partner.signature_key.ca_cert:
                ca_cert = str(message.partner.signature_key.ca_cert.path)
            verify_cert = message.partner.signature_key.verify_cert

            # Extract the signed message and signature
            main_boundary = '--' + mdn_message.get_boundary()
            for part in mdn_message.get_payload():
                if part.get_content_type().lower() in [
                        "application/pkcs7-signature",
                        "application/x-pkcs7-signature"
                ]:
                    mdn_content, __ = as2utils.check_binary_sig(
                        part, main_boundary, mdn_content)
                else:
                    mdn_message = part

            # Verify the signature using raw MDN content
            try:
                as2utils.verify_payload(mdn_content, None, cert, ca_cert,
                                        verify_cert)
            except Exception, e:
                raise as2utils.As2Exception(
                    _(u'MDN Signature Verification Error, exception message is %s'
                      % e))

        # Save the MDN to the store
        filename = message_id.strip('<>') + '.mdn'
        full_filename = as2utils.storefile(
            pyas2init.gsettings['mdn_receive_store'], filename,
            as2utils.extractpayload(mdn_message), True)
        message.mdn = models.MDN.objects.create(
            message_id=message_id.strip('<>'),
            file=full_filename,
            status='R',
            headers=mdn_headers,
            signed=mdn_signed)

        # Process the MDN report to extract the AS2 message status
        if mdn_message.get_content_type() == 'multipart/report':
            for part in mdn_message.walk():
                if part.get_content_type(
                ) == 'message/disposition-notification':
                    pyas2init.logger.debug(
                        'Found MDN report for message %s:\n%s' %
                        (message.message_id, part.as_string()))
                    models.Log.objects.create(
                        message=message,
                        status='S',
                        text=_(u'Checking the MDN for status of the message'))
                    mdn = part.get_payload().pop()
                    mdn_status = mdn.get('Disposition').split(';')
                    # Check the status of the AS2 message
                    if mdn_status[1].strip() == 'processed':
                        models.Log.objects.create(
                            message=message,
                            status='S',
                            text=_(u'Message has been successfully processed, '
                                   u'verifying the MIC if present.'))
                        # Compare the MIC of the received message
                        if mdn.get('Received-Content-MIC') and message.mic:
                            mdn_mic = mdn.get('Received-Content-MIC').split(
                                ',')
                            if message.mic != mdn_mic[0]:
                                message.status = 'W'
                                models.Log.objects.create(
                                    message=message,
                                    status='W',
                                    text=_(
                                        u'Message Integrity check failed, please validate '
                                        u'message content with your partner'))
                            else:
                                message.status = 'S'
                                models.Log.objects.create(
                                    message=message,
                                    status='S',
                                    text=
                                    _(u'File Transferred successfully to the partner'
                                      ))
                        else:
                            message.status = 'S'
                            models.Log.objects.create(
                                message=message,
                                status='S',
                                text=
                                _(u'File Transferred successfully to the partner'
                                  ))

                        # Run the post successful send command
                        run_post_send(message)
                    else:
                        raise as2utils.As2Exception(
                            _(u'Partner failed to process file. '
                              u'MDN status is %s' % mdn.get('Disposition')))
        else:
            raise as2utils.As2Exception(
                _(u'MDN report not found in the response'))
예제 #2
0
파일: as2lib.py 프로젝트: kurohai/pyas2
def save_mdn(message, mdn_content):
    """ Process the received MDN and check status of sent message. Takes the raw mdn as input, verifies the signature
    if present and the extracts the status of the original message."""

    try:
        # Parse the raw mdn to an email.Message
        mdn_message = email.message_from_string(mdn_content)
        mdn_headers = ''
        for key in mdn_message.keys():
            mdn_headers += '%s: %s\n' % (key, mdn_message[key])
        message_id = mdn_message.get('message-id')

        # Raise error if message is not an MDN
        if mdn_message.get_content_type() not in ['multipart/signed', 'multipart/report']:
            raise as2utils.As2Exception(_(u'MDN report not found in the response'))

        # Raise error if signed MDN requested and unsigned MDN returned
        if message.partner.mdn_sign and mdn_message.get_content_type() != 'multipart/signed':
            models.Log.objects.create(message=message,
                                      status='W',
                                      text=_(u'Expected signed MDN but unsigned MDN returned'))

        mdn_signed = False
        if mdn_message.get_content_type() == 'multipart/signed':
            # Verify the signature in the MDN message
            models.Log.objects.create(message=message,
                                      status='S',
                                      text=_(u'Verifying the signed MDN with partner key {0:s}'.format(
                                          message.partner.signature_key)))
            mdn_signed = True

            # Get the partners public and ca certificates
            cert = str(message.partner.signature_key.certificate.path)
            ca_cert = cert
            if message.partner.signature_key.ca_cert:
                ca_cert = str(message.partner.signature_key.ca_cert.path)
            verify_cert = message.partner.signature_key.verify_cert

            # Extract the signed message and signature
            main_boundary = '--' + mdn_message.get_boundary()
            for part in mdn_message.get_payload():
                if part.get_content_type().lower() == "application/pkcs7-signature":
                    mdn_content, __ = as2utils.check_binary_sig(
                        part, main_boundary, mdn_content)
                else:
                    mdn_message = part

            # Verify the signature using raw MDN content
            try:
                as2utils.verify_payload(mdn_content, None, cert, ca_cert, verify_cert)
            except Exception, e:
                raise as2utils.As2Exception(_(u'MDN Signature Verification Error, exception message is %s' % e))

        # Save the MDN to the store
        filename = message_id.strip('<>') + '.mdn'
        full_filename = as2utils.storefile(pyas2init.gsettings['mdn_receive_store'],
                                           filename,
                                           as2utils.extractpayload(mdn_message),
                                           True)
        message.mdn = models.MDN.objects.create(message_id=message_id.strip('<>'),
                                                file=full_filename,
                                                status='R',
                                                headers=mdn_headers,
                                                signed=mdn_signed)

        # Process the MDN report to extract the AS2 message status
        if mdn_message.get_content_type() == 'multipart/report':
            for part in mdn_message.walk():
                if part.get_content_type() == 'message/disposition-notification':
                    pyas2init.logger.debug('Found MDN report for message %s:\n%s' % (message.message_id,
                                                                                     part.as_string()))
                    models.Log.objects.create(message=message,
                                              status='S',
                                              text=_(u'Checking the MDN for status of the message'))
                    mdn = part.get_payload().pop()
                    mdn_status = mdn.get('Disposition').split(';')
                    # Check the status of the AS2 message
                    if mdn_status[1].strip() == 'processed':
                        models.Log.objects.create(message=message,
                                                  status='S',
                                                  text=_(u'Message has been successfully processed, '
                                                         u'verifying the MIC if present.'))
                        # Compare the MIC of the received message
                        if mdn.get('Received-Content-MIC') and message.mic:
                            mdn_mic = mdn.get('Received-Content-MIC').split(',')
                            if message.mic != mdn_mic[0]:
                                message.status = 'W'
                                models.Log.objects.create(message=message,
                                                          status='W',
                                                          text=_(u'Message Integrity check failed, please validate '
                                                                 u'message content with your partner'))
                            else:
                                message.status = 'S'
                                models.Log.objects.create(message=message,
                                                          status='S',
                                                          text=_(u'File Transferred successfully to the partner'))
                        else:
                            message.status = 'S'
                            models.Log.objects.create(message=message,
                                                      status='S',
                                                      text=_(u'File Transferred successfully to the partner'))

                        # Run the post successful send command
                        run_post_send(message)
                    else:
                        raise as2utils.As2Exception(_(u'Partner failed to process file. '
                                                      u'MDN status is %s' % mdn.get('Disposition')))
        else:
            raise as2utils.As2Exception(_(u'MDN report not found in the response'))
예제 #3
0
파일: as2lib.py 프로젝트: VDuda/pyas2
def save_message(message, payload, raw_payload):
    """ Function decompresses, decrypts and verifies the received AS2 message
     Takes an AS2 message as input and returns the actual payload ex. X12 message """

    try:
        # Initialize variables
        mic_content = None
        mic_alg = None
        filename = payload.get_filename()

        # Search for the organization adn partner, raise error if none exists.
        models.Log.objects.create(
            message=message,
            status='S',
            text=_(u'Begin Processing of received AS2 message'))

        if not models.Organization.objects.filter(
                as2_name=as2utils.unescape_as2name(payload.get(
                    'as2-to'))).exists():
            raise as2utils.As2PartnerNotFound(
                'Unknown AS2 organization with id %s' % payload.get('as2-to'))
        message.organization = models.Organization.objects.get(
            as2_name=as2utils.unescape_as2name(payload.get('as2-to')))

        if not models.Partner.objects.filter(
                as2_name=as2utils.unescape_as2name(payload.get(
                    'as2-from'))).exists():
            raise as2utils.As2PartnerNotFound(
                'Unknown AS2 Trading partner with id %s' %
                payload.get('as2-from'))
        message.partner = models.Partner.objects.get(
            as2_name=as2utils.unescape_as2name(payload.get('as2-from')))
        models.Log.objects.create(
            message=message,
            status='S',
            text=_(u'Message is for Organization "%s" from partner "%s"' %
                   (message.organization, message.partner)))

        # Check if message from this partner are expected to be encrypted
        if message.partner.encryption and payload.get_content_type(
        ) != 'application/pkcs7-mime':
            raise as2utils.As2InsufficientSecurity(
                u'Incoming messages from AS2 partner {0:s} are defined to be encrypted'
                .format(message.partner.as2_name))

        # Check if payload is encrypted and if so decrypt it
        if payload.get_content_type() == 'application/pkcs7-mime' \
                and payload.get_param('smime-type') == 'enveloped-data':
            models.Log.objects.create(
                message=message,
                status='S',
                text=_(
                    u'Decrypting the payload using private key {0:s}'.format(
                        message.organization.encryption_key)))
            message.encrypted = True

            # Check if encrypted data is base64 encoded, if not then encode
            try:
                payload.get_payload().encode('ascii')
            except UnicodeDecodeError:
                payload.set_payload(payload.get_payload().encode('base64'))

            # Decrypt the base64 encoded data using the partners public key
            pyas2init.logger.debug(u'Decrypting the payload :\n{0:s}'.format(
                payload.get_payload()))
            try:
                decrypted_content = as2utils.decrypt_payload(
                    as2utils.mimetostring(payload, 78),
                    str(message.organization.encryption_key.certificate.path),
                    str(message.organization.encryption_key.
                        certificate_passphrase))
                raw_payload = decrypted_content
                payload = email.message_from_string(decrypted_content)

                # Check if decrypted content is the actual content i.e. no compression and no signatures
                if payload.get_content_type() == 'text/plain':
                    payload = email.Message.Message()
                    payload.set_payload(decrypted_content)
                    payload.set_type('application/edi-consent')
                    if filename:
                        payload.add_header('Content-Disposition',
                                           'attachment',
                                           filename=filename)
            except Exception, msg:
                raise as2utils.As2DecryptionFailed(
                    'Failed to decrypt message, exception message is %s' % msg)

        # Check if message from this partner are expected to be signed
        if message.partner.signature and payload.get_content_type(
        ) != 'multipart/signed':
            raise as2utils.As2InsufficientSecurity(
                u'Incoming messages from AS2 partner {0:s} are defined to be signed'
                .format(message.partner.as2_name))

        # Check if message is signed and if so verify it
        if payload.get_content_type() == 'multipart/signed':
            if not message.partner.signature_key:
                raise as2utils.As2InsufficientSecurity(
                    'Partner has no signature verification key defined')
            models.Log.objects.create(
                message=message,
                status='S',
                text=_(
                    u'Message is signed, Verifying it using public key {0:s}'.
                    format(message.partner.signature_key)))
            pyas2init.logger.debug(
                'Verifying the signed payload:\n{0:s}'.format(
                    payload.as_string()))
            message.signed = True
            mic_alg = payload.get_param('micalg').lower() or 'sha1'

            # Get the partners public and ca certificates
            cert = str(message.partner.signature_key.certificate.path)
            ca_cert = cert
            if message.partner.signature_key.ca_cert:
                ca_cert = str(message.partner.signature_key.ca_cert.path)
            verify_cert = message.partner.signature_key.verify_cert

            # Extract the signature and signed content from the mime message
            main_boundary = '--' + payload.get_boundary()
            for part in payload.walk():
                if part.get_content_type() in [
                        "application/pkcs7-signature",
                        "application/x-pkcs7-signature"
                ]:
                    __, raw_sig = as2utils.check_binary_sig(
                        part, main_boundary, raw_payload)
                else:
                    payload = part

            # Verify message using raw payload received from partner
            try:
                as2utils.verify_payload(raw_payload, None, cert, ca_cert,
                                        verify_cert)
            except Exception:
                # Verify message using extracted signature and canonicalzed message
                try:
                    as2utils.verify_payload(as2utils.canonicalize2(payload),
                                            raw_sig, cert, ca_cert,
                                            verify_cert)
                except Exception, e:
                    raise as2utils.As2InvalidSignature(
                        'Signature Verification Failed, exception message is {0:s}'
                        .format(e))

            mic_content = as2utils.canonicalize2(payload)
예제 #4
0
파일: as2lib.py 프로젝트: kurohai/pyas2
def save_message(message, payload, raw_payload):
    """ Function decompresses, decrypts and verifies the received AS2 message
     Takes an AS2 message as input and returns the actual payload ex. X12 message """

    try:
        # Initialize variables
        mic_content = None
        mic_alg = None
        filename = payload.get_filename()

        # Search for the organization adn partner, raise error if none exists.
        models.Log.objects.create(message=message, status='S', text=_(u'Begin Processing of received AS2 message'))

        if not models.Organization.objects.filter(as2_name=as2utils.unescape_as2name(payload.get('as2-to'))).exists():
            raise as2utils.As2PartnerNotFound('Unknown AS2 organization with id %s' % payload.get('as2-to'))
        message.organization = models.Organization.objects.get(
            as2_name=as2utils.unescape_as2name(payload.get('as2-to')))

        if not models.Partner.objects.filter(as2_name=as2utils.unescape_as2name(payload.get('as2-from'))).exists():
            raise as2utils.As2PartnerNotFound('Unknown AS2 Trading partner with id %s' % payload.get('as2-from'))
        message.partner = models.Partner.objects.get(as2_name=as2utils.unescape_as2name(payload.get('as2-from')))
        models.Log.objects.create(
            message=message,
            status='S',
            text=_(u'Message is for Organization "%s" from partner "%s"' % (message.organization, message.partner))
         )

        # Check if message from this partner are expected to be encrypted
        if message.partner.encryption and payload.get_content_type() != 'application/pkcs7-mime':
            raise as2utils.As2InsufficientSecurity(
                u'Incoming messages from AS2 partner {0:s} are defined to be encrypted'.format(
                    message.partner.as2_name))

        # Check if payload is encrypted and if so decrypt it
        if payload.get_content_type() == 'application/pkcs7-mime' \
                and payload.get_param('smime-type') == 'enveloped-data':
            models.Log.objects.create(message=message, status='S', text=_(
                u'Decrypting the payload using private key {0:s}'.format(message.organization.encryption_key)))
            message.encrypted = True

            # Check if encrypted data is base64 encoded, if not then encode
            try:
                payload.get_payload().encode('ascii')
            except UnicodeDecodeError:
                payload.set_payload(payload.get_payload().encode('base64'))

            # Decrypt the base64 encoded data using the partners public key
            pyas2init.logger.debug(u'Decrypting the payload :\n{0:s}'.format(payload.get_payload()))
            try:
                decrypted_content = as2utils.decrypt_payload(
                    as2utils.mimetostring(payload, 78),
                    str(message.organization.encryption_key.certificate.path),
                    str(message.organization.encryption_key.certificate_passphrase)
                )
                raw_payload = decrypted_content
                payload = email.message_from_string(decrypted_content)

                # Check if decrypted content is the actual content i.e. no compression and no signatures
                if payload.get_content_type() == 'text/plain':
                    payload = email.Message.Message()
                    payload.set_payload(decrypted_content)
                    payload.set_type('application/edi-consent')
                    if filename:
                        payload.add_header('Content-Disposition', 'attachment', filename=filename)
            except Exception, msg:
                raise as2utils.As2DecryptionFailed('Failed to decrypt message, exception message is %s' % msg)

        # Check if message from this partner are expected to be signed
        if message.partner.signature and payload.get_content_type() != 'multipart/signed':
            raise as2utils.As2InsufficientSecurity(
                u'Incoming messages from AS2 partner {0:s} are defined to be signed'.format(message.partner.as2_name))

        # Check if message is signed and if so verify it
        if payload.get_content_type() == 'multipart/signed':
            if not message.partner.signature_key:
                raise as2utils.As2InsufficientSecurity('Partner has no signature verification key defined')
            models.Log.objects.create(message=message, status='S', text=_(
                u'Message is signed, Verifying it using public key {0:s}'.format(message.partner.signature_key)))
            pyas2init.logger.debug('Verifying the signed payload:\n{0:s}'.format(payload.as_string()))
            message.signed = True
            mic_alg = payload.get_param('micalg').lower() or 'sha1'

            # Get the partners public and ca certificates
            cert = str(message.partner.signature_key.certificate.path)
            ca_cert = cert
            if message.partner.signature_key.ca_cert:
                ca_cert = str(message.partner.signature_key.ca_cert.path)
            verify_cert = message.partner.signature_key.verify_cert

            # Extract the signature and signed content from the mime message
            main_boundary = '--' + payload.get_boundary()
            for part in payload.walk():
                if part.get_content_type() == "application/pkcs7-signature":
                    __, raw_sig = as2utils.check_binary_sig(part, main_boundary, raw_payload)
                else:
                    payload = part

            # Verify message using raw payload received from partner
            try:
                as2utils.verify_payload(raw_payload, None, cert, ca_cert, verify_cert)
            except Exception:
                # Verify message using extracted signature and canonicalzed message
                try:
                    as2utils.verify_payload(as2utils.canonicalize2(payload), raw_sig, cert, ca_cert, verify_cert)
                except Exception, e:
                    raise as2utils.As2InvalidSignature(
                        'Signature Verification Failed, exception message is {0:s}'.format(e))

            mic_content = as2utils.canonicalize2(payload)