def test_encrypted_signed_compressed_message(self): """ Test Encrypted Signed Compressed Message """ # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.encrypt = True self.partner.compress = True out_message = as2.Message(self.org, self.partner) out_message.build(self.test_data) raw_out_message = out_message.headers_str + b"\r\n" + out_message.content # Parse the generated AS2 message as the partner in_message = as2.Message() status, _, _ = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, ) # Compare the mic contents of the input and output messages self.assertEqual(status, "processed") self.assertTrue(in_message.signed) self.assertTrue(in_message.encrypted) self.assertTrue(in_message.compressed) self.assertEqual(out_message.mic, in_message.mic) self.assertEqual(self.test_data.splitlines(), in_message.content.splitlines())
def test_message_checks(self): """Test the checks and other features of Message.""" msg = as2.Message() assert msg.content == "" assert msg.headers == {} assert msg.headers_str == b"" msg.payload = message.Message() msg.payload.set_payload(b"data") assert msg.content == b"data" org = as2.Organization(as2_name="AS2 Server") partner = as2.Partner(as2_name="AS2 Partner", sign=True) msg = as2.Message(sender=org, receiver=partner) with self.assertRaises(ImproperlyConfigured): msg.build(b"data") msg.receiver.sign = False msg.receiver.encrypt = True with self.assertRaises(ImproperlyConfigured): msg.build(b"data") msg.receiver.encrypt = False msg.receiver.mdn_mode = "ASYNC" with self.assertRaises(ImproperlyConfigured): msg.build(b"data") msg.sender.mdn_url = "http://localhost/pyas2/as2receive" msg.build(b"data")
def test_insufficient_security(self): """ Test case where message security is not as per the configuration """ # Build an As2 message to be transmitted to partner self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner self.partner.encrypt = True raw_out_message = \ self.out_message.headers_str + b'\r\n' + self.out_message.content in_message = as2.Message() status, (exc, _), mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False ) self.assertEqual(status, 'processed/Error') self.assertEqual(exc.disposition_modifier, 'insufficient-message-security') # Try again for signing check self.partner.encrypt = False self.partner.sign = True in_message = as2.Message() status, (exc, _), mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False ) self.assertEqual(status, 'processed/Error') self.assertEqual(exc.disposition_modifier, 'insufficient-message-security')
def test_binary_message(self): """ Test Encrypted Signed Binary Message """ # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.encrypt = True self.partner.compress = True out_message = as2.Message(self.org, self.partner) test_message_path = os.path.join(TEST_DIR, "payload.binary") with open(test_message_path, "rb") as bin_file: original_message = bin_file.read() out_message.build( original_message, filename="payload.binary", content_type="application/octet-stream", ) raw_out_message = out_message.headers_str + b"\r\n" + out_message.content # Parse the generated AS2 message as the partner in_message = as2.Message() status, _, _ = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False, ) # Compare the mic contents of the input and output messages self.assertEqual(status, "processed") self.assertEqual(original_message, in_message.payload.get_payload(decode=True)) self.assertTrue(in_message.signed) self.assertTrue(in_message.encrypted) self.assertEqual(out_message.mic, in_message.mic)
def test_failed_decompression(self): """ Test case where message decompression has failed """ # Build an As2 message to be transmitted to partner self.partner.compress = True self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = (self.out_message.headers_str + b"\r\n" + base64.b64encode(b"xxxxx")) in_message = as2.Message() _, exec_info, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, ) out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b"\r\n" + mdn.content, find_message_cb=self.find_message) self.assertEqual(status, "processed/Error") self.assertEqual(detailed_status, "decompression-failed")
def test_failed_signature(self): """ Test case where signature verification has failed """ # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.verify_cert = self.mecas2_public_key self.partner.validate_certs = False self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = (self.out_message.headers_str + b"\r\n" + self.out_message.content) in_message = as2.Message() _, exec_info, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False, ) out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b"\r\n" + mdn.content, find_message_cb=self.find_message) self.assertEqual(status, "processed/Error") self.assertEqual(detailed_status, "authentication-failed")
def test_failed_decryption(self): """ Test case where message decryption has failed """ # Build an As2 message to be transmitted to partner self.partner.encrypt = True self.partner.encrypt_cert = self.mecas2_public_key self.partner.validate_certs = False self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = \ self.out_message.headers_str + b'\r\n' + self.out_message.content in_message = as2.Message() _, exec_info, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False ) out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b'\r\n' + mdn.content, find_message_cb=self.find_message ) self.assertEqual(status, 'processed/Error') self.assertEqual(detailed_status, 'decryption-failed')
def test_duplicate_message(self): """ Test case where a duplicate message is sent to the partner """ # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.encrypt = True self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = (self.out_message.headers_str + b"\r\n" + self.out_message.content) in_message = as2.Message() _, _, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: True, ) out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b"\r\n" + mdn.content, find_message_cb=self.find_message) self.assertEqual(status, "processed/Warning") self.assertEqual(detailed_status, "duplicate-document")
def test_signed_mdn(self): """ Test signed MDN generation and parsing """ # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.encrypt = True self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.partner.mdn_digest_alg = "sha256" self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = ( self.out_message.headers_str + b"\r\n" + self.out_message.content ) in_message = as2.Message() _, _, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, ) out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b"\r\n" + mdn.content, find_message_cb=self.find_message ) self.assertEqual(status, "processed")
def test_non_matching_mic(self): """Test the case where a the mic in the mdn does not match the mic in the message.""" self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.partner.sign = True self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = (self.out_message.headers_str + b"\r\n" + self.out_message.content) in_message = as2.Message() _, _, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False, ) # Set the mdn sig alg and parse it self.out_message.mic = b"dummy value" out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b"\r\n" + mdn.content, find_message_cb=self.find_message) self.assertEqual(status, "processed/warning") self.assertEqual(detailed_status, "Message Integrity check failed.")
def test_unsigned_mdn_sent_error(self): """Test the case where a signed mdn was expected but unsigned mdn was returned.""" self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = (self.out_message.headers_str + b"\r\n" + self.out_message.content) in_message = as2.Message() _, _, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False, ) # Set the mdn sig alg and parse it self.partner.mdn_digest_alg = "sha256" out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b"\r\n" + mdn.content, find_message_cb=self.find_message) self.assertEqual(status, "failed/Failure") self.assertEqual(detailed_status, "Expected signed MDN but unsigned MDN returned")
def test_failed_mdn_parse(self): """Test mdn parsing failures are captured.""" # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.encrypt = True self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.partner.mdn_digest_alg = 'sha256' self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = \ self.out_message.headers_str + b'\r\n' + self.out_message.content in_message = as2.Message() _, _, mdn = in_message.parse(raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner) out_mdn = as2.Mdn() self.partner.verify_cert = self.mecas2_public_key self.partner.validate_certs = False status, detailed_status = out_mdn.parse( mdn.headers_str + b'\r\n' + mdn.content, find_message_cb=self.find_message) self.assertEqual(status, 'failed/Failure') self.assertEqual( detailed_status, 'Failed to parse received MDN. Failed to verify message signature: ' 'Message Digest does not match.')
def test_partner_not_found(self): """ Test case where partner and organization is not found """ # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.encrypt = True self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the generated AS2 message as the partner raw_out_message = \ self.out_message.headers_str + b'\r\n' + self.out_message.content in_message = as2.Message() _, _, mdn = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=lambda x: None, find_message_cb=lambda x, y: False ) out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b'\r\n' + mdn.content, find_message_cb=self.find_message ) self.assertEqual(status, 'processed/Error') self.assertEqual(detailed_status, 'unknown-trading-partner') # Parse again but this time make without organization in_message = as2.Message() _, _, mdn = in_message.parse( raw_out_message, find_org_cb=lambda x: None, find_partner_cb=self.find_partner, find_message_cb=lambda x, y: False ) out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( mdn.headers_str + b'\r\n' + mdn.content, find_message_cb=self.find_message ) self.assertEqual(status, 'processed/Error') self.assertEqual(detailed_status, 'unknown-trading-partner')
def test_plain_message(self): """ Test Unencrypted Unsigned Uncompressed Message """ # Build an As2 message to be transmitted to partner out_message = as2.Message(self.org, self.partner) out_message.build(self.test_data) raw_out_message = \ out_message.headers_str + b'\r\n' + out_message.content # Parse the generated AS2 message as the partner in_message = as2.Message() status, _, _ = in_message.parse(raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner) # Compare contents of the input and output messages self.assertEqual(status, 'processed') self.assertEqual(self.test_data, in_message.content)
def test_process_mdn(self): """ Test processing mdn received from Sterling Integrator""" msg = as2.Message(sender=self.org, receiver=self.partner) msg.message_id = '*****@*****.**' as2mdn = as2.Mdn() # Parse the mdn and get the message status with open(os.path.join(TEST_DIR, 'sb2bi_signed.mdn'), 'rb') as mdn: status, detailed_status = as2mdn.parse(mdn.read(), lambda x, y: msg) self.assertEqual(status, 'processed')
def test_process_message(self): """ Test processing message received from Sterling Integrator""" with open(os.path.join(TEST_DIR, "sb2bi_signed_cmp.msg"), "rb") as msg: as2message = as2.Message() status, exception, as2mdn = as2message.parse( msg.read(), lambda x: self.org, lambda y: self.partner, lambda x, y: False, ) self.assertEqual(status, "processed")
def test_encrypted_signed_message_dos(self): """ Test Encrypted Signed Uncompressed Message with DOS line endings. """ # Build an As2 message to be transmitted to partner self.partner.sign = True self.partner.encrypt = True out_message = as2.Message(self.org, self.partner) out_message.build(self.test_data_dos) raw_out_message = out_message.headers_str + b'\r\n' + out_message.content # Parse the generated AS2 message as the partner in_message = as2.Message() status, _, _ = in_message.parse(raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner) # Compare the mic contents of the input and output messages self.assertEqual(status, 'processed') self.assertTrue(in_message.signed) self.assertTrue(in_message.encrypted) self.assertEqual(out_message.mic, in_message.mic) self.assertEqual(self.test_data_dos, in_message.content)
def test_compressed_message(self): """ Test Compressed Message received from Mendelson AS2""" # Parse the generated AS2 message as the partner received_file = os.path.join(TEST_DIR, 'mecas2_compressed.as2') with open(received_file, 'rb') as fp: in_message = as2.Message() in_message.parse(fp.read(), find_org_cb=self.find_org, find_partner_cb=self.find_partner) # Compare the mic contents of the input and output messages self.assertTrue(in_message.compressed) self.assertEqual(self.test_data, in_message.content)
def test_signed_message(self): """ Test Unencrypted Signed Uncompressed Message from Mendelson AS2""" # Parse the generated AS2 message as the partner received_file = os.path.join(TEST_DIR, "mecas2_signed.as2") with open(received_file, "rb") as fp: in_message = as2.Message() in_message.parse(fp.read(), find_org_cb=self.find_org, find_partner_cb=self.find_partner) # Compare the mic contents of the input and output messages self.assertTrue(in_message.signed) self.assertEqual(in_message.digest_alg, "sha1") self.assertEqual(self.test_data, in_message.content)
def test_all_encryption_algos(self): """Test all the available encryption algorithms.""" algos = ['rc2_128_cbc', 'rc4_128_cbc', 'aes_128_cbc', 'aes_192_cbc', 'aes_256_cbc'] for algo in algos: # Build an As2 message to be transmitted to partner self.partner.encrypt = True self.partner.enc_alg = algo out_message = as2.Message(self.org, self.partner) out_message.build(self.test_data) raw_out_message = out_message.headers_str + b'\r\n' + out_message.content # Parse the generated AS2 message as the partner in_message = as2.Message() status, _, _ = in_message.parse( raw_out_message, find_org_cb=self.find_org, find_partner_cb=self.find_partner ) # Compare the mic contents of the input and output messages self.assertEqual(status, 'processed') self.assertTrue(in_message.encrypted) self.assertEqual(self.test_data.splitlines(), in_message.content.splitlines())
def test_mdn_not_found(self): """Test that the MDN parser raises MDN not found when a non MDN message is passed.""" self.partner.encrypt = True self.partner.validate_certs = False self.partner.mdn_mode = as2.SYNCHRONOUS_MDN self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) # Parse the AS2 message as an MDN mdn = as2.Mdn() raw_out_message = (self.out_message.headers_str + b"\r\n" + self.out_message.content) status, detailed_status = mdn.parse(raw_out_message, find_message_cb=self.find_message) self.assertEqual(status, "failed/Failure") self.assertEqual(detailed_status, "mdn-not-found")
def test_encrypted_signed_compressed_message(self): """ Test Encrypted Signed Compressed Message from Mendelson AS2""" # Parse the generated AS2 message as the partner received_file = os.path.join(TEST_DIR, 'mecas2_compressed_signed_encrypted.as2') with open(received_file, 'rb') as fp: in_message = as2.Message() in_message.parse(fp.read(), find_org_cb=self.find_org, find_partner_cb=self.find_partner) # Compare the mic contents of the input and output messages self.assertTrue(in_message.encrypted) self.assertEqual(in_message.enc_alg, 'tripledes_192_cbc') self.assertTrue(in_message.signed) self.assertEqual(in_message.digest_alg, 'sha1') self.assertEqual(self.test_data, in_message.content)
def test_encrypted_message(self): """ Send Encrypted Unsigned Uncompressed Message to Mendelson AS2""" self.partner.encrypt = True self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) response = requests.post('http://localhost:8080/pyas2/as2receive', headers=self.out_message.headers, data=self.out_message.content) raw_mdn = '' for k, v in response.headers.items(): raw_mdn += '{}: {}\n'.format(k, v) raw_mdn = raw_mdn + '\n' + response.text out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( raw_mdn, find_message_cb=self.find_message) self.assertEqual(status, 'processed')
def test_signed_message(self): """ Send Unencrypted Signed Uncompressed Message to Mendelson AS2""" self.partner.sign = True self.out_message = as2.Message(self.org, self.partner) self.out_message.build(self.test_data) response = requests.post( "http://localhost:8080/pyas2/as2receive", data=self.out_message.content, headers=self.out_message.headers, ) raw_mdn = "" for k, v in response.headers.items(): raw_mdn += "{}: {}\n".format(k, v) raw_mdn = raw_mdn + "\n" + response.text out_mdn = as2.Mdn() status, detailed_status = out_mdn.parse( raw_mdn, find_message_cb=self.find_message) self.assertEqual(status, "processed")
def find_message(self, message_id, message_recipient): message = as2.Message() message.sender = self.org message.receiver = self.partner message.mic = b"O4bvrm5t2YunRfwvZicNdEUmPaPZ9vUslX8loVLDck0=" return message