Skip to content

Commit 0e753e4

Browse files
authored
Merge pull request #15 from messagemedia/feature/MAPI-81-support-12275-investigate-python
Fixed the issue where in the value of the request header x-Content-MD5 is not the MD5 of the body.
2 parents efef3c3 + 94f49b8 commit 0e753e4

File tree

11 files changed

+162
-18
lines changed

11 files changed

+162
-18
lines changed

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
*.pyc
2-
index.py
2+
index.py
3+
build
4+
dist
5+
.idea
6+
*egg-info

message_media_messages/configuration.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66
This file was automatically generated for MessageMedia by APIMATIC v2.0 ( https://apimatic.io ).
77
"""
88

9-
from message_media_messages.api_helper import APIHelper
10-
119

1210
class Configuration(object):
13-
1411
"""A class used for configuring the SDK by a user.
1512
1613
This class need not be instantiated and all properties and methods
@@ -35,8 +32,9 @@ class Configuration(object):
3532

3633
# The username to use with HMAC authentication
3734
# TODO: Set an appropriate value
38-
hmac_auth_user_name = None
35+
hmac_auth_user_name = 'TODO: Replace'
3936

4037
# The password to use with HMAC authentication
4138
# TODO: Set an appropriate value
42-
hmac_auth_password = None
39+
hmac_auth_password = 'TODO: Replace'
40+
Binary file not shown.

message_media_messages/controllers/messages_controller.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def get_message_status(self,
7272

7373
# Prepare query URL
7474
_url_path = '/v1/messages/{messageId}'
75-
_url_path = APIHelper.append_url_with_template_parameters(_url_path, {
75+
_url_path = APIHelper.append_url_with_template_parameters(_url_path, {
7676
'messageId': message_id
7777
})
7878
_query_builder = Configuration.base_uri
@@ -299,7 +299,7 @@ def cancel_scheduled_message(self,
299299

300300
# Prepare query URL
301301
_url_path = '/v1/messages/{messageId}'
302-
_url_path = APIHelper.append_url_with_template_parameters(_url_path, {
302+
_url_path = APIHelper.append_url_with_template_parameters(_url_path, {
303303
'messageId': message_id
304304
})
305305
_query_builder = Configuration.base_uri

message_media_messages/http/auth/auth_manager.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ def apply_hmac_auth(http_request, url, body=None):
7878
if body is not None:
7979
request_type = "POST"
8080
m = hashlib.md5()
81+
m.update(bytes(body, 'utf-8'))
8182
content_hash = m.hexdigest()
8283
content_signature = "x-Content-MD5: {}\n".format(content_hash)
8384
content_header = "x-Content-MD5 "

requirements.txt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
requests==2.20.0
2-
jsonpickle==0.7.1
3-
cachecontrol==0.11.7
4-
python-dateutil==2.5.3
1+
requests==2.28.2
2+
jsonpickle==3.0.1
3+
cachecontrol==0.12.11
4+
python-dateutil==2.8.2
5+
responses~=0.22.0
6+
urllib3~=1.26.14
7+
setuptools==67.2.0

setup.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setup(
1010
name='messagemedia-messages-sdk',
11-
version='2.1.0',
11+
version='2.1.1',
1212
description='The MessageMedia Messages API provides a number of endpoints for building powerful two-way messaging applications.',
1313
long_description_content_type="text/markdown",
1414
long_description=long_description,
@@ -17,9 +17,12 @@
1717
url='https://developers.messagemedia.com',
1818
packages=find_packages(),
1919
install_requires=[
20-
'requests>=2.9.1, <3.0',
21-
'jsonpickle>=0.7.1, <1.0',
22-
'cachecontrol>=0.11.7, <1.0',
23-
'python-dateutil>=2.5.3, <3.0'
20+
'requests>=2.28.2, <3.0',
21+
'jsonpickle>=3.0.1, <4.0',
22+
'cachecontrol>=0.12.11, <1.0',
23+
'python-dateutil>=2.8.2, <3.0',
24+
'responses>=0.22.0, <1.0',
25+
'urllib3>=1.26.14, <2.0',
26+
'setuptools>=67.2.0, <68'
2427
]
2528
)

test-requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
nose==1.3.7
1+
nose==1.3.7
2+
freezegun==1.2.2

tests/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__all__ = [
2+
'auth_manager_test',
3+
'test_util'
4+
]

tests/auth_manager_test.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# -*- coding: utf-8 -*-
2+
3+
import hashlib
4+
import unittest
5+
6+
from freezegun import freeze_time
7+
8+
from message_media_messages.api_helper import APIHelper
9+
from message_media_messages.configuration import Configuration
10+
from message_media_messages.http.auth.auth_manager import AuthManager
11+
from message_media_messages.http.requests_client import RequestsClient
12+
from message_media_messages.models.format_enum import FormatEnum
13+
from message_media_messages.models.message import Message
14+
from message_media_messages.models.send_messages_request import SendMessagesRequest
15+
from tests.test_util import TestUtil
16+
17+
18+
class AuthManagerTest(unittest.TestCase):
19+
20+
def __init__(self, method_name: str = ...):
21+
super().__init__(method_name)
22+
self.content_hash = None
23+
self.query_url = None
24+
self.send_message_request = None
25+
26+
def setUp(self):
27+
self.send_message_request = self.get_send_message_request()
28+
self.query_url = APIHelper.clean_url(Configuration.base_uri + '/v1/messages')
29+
self.content_hash = self.get_content_hash(self.send_message_request)
30+
self.content_md5_header = "x-Content-MD5: {}\n".format(self.content_hash)
31+
self.date_header = 'Wed, 08 Feb 2023 03:00:00 GMT'
32+
self.expected_algorithm = ' algorithm="hmac-sha1"'
33+
Configuration.hmac_auth_user_name = "some_user_name"
34+
self.expected_username = "hmac username=\"" + Configuration.hmac_auth_user_name + "\""
35+
36+
@freeze_time("2023-02-08 14:00:00")
37+
def test_post_request_hmac_authorization_header_values_are_appropriate(self):
38+
body = APIHelper.json_serialize(self.send_message_request)
39+
40+
request = RequestsClient().post(
41+
query_url=self.query_url,
42+
parameters=body,
43+
headers={}
44+
)
45+
46+
AuthManager.apply_hmac_auth(request, self.query_url, body)
47+
48+
expected_headers_property = ' headers="date x-Content-MD5 request-line"'
49+
expected_signature = TestUtil.create_signature(self.date_header, self.content_md5_header,
50+
self.query_url, 'POST', True)
51+
self.assert_auth_header(request, expected_headers_property, expected_signature)
52+
53+
def test_post_request_content_md5_is_md5_of_request_body(self):
54+
body = APIHelper.json_serialize(self.send_message_request)
55+
56+
request = RequestsClient().post(
57+
query_url=self.query_url,
58+
parameters=body,
59+
headers={}
60+
)
61+
62+
AuthManager.apply_hmac_auth(request, self.query_url, body)
63+
request_md5 = request.headers['x-Content-MD5']
64+
assert self.content_hash == request_md5
65+
66+
@freeze_time("2023-02-08 14:00:00")
67+
def test_get_request_hmac_authorization_header_values_are_appropriate(self):
68+
request = RequestsClient().get(
69+
query_url=self.query_url,
70+
headers={}
71+
)
72+
73+
AuthManager.apply_hmac_auth(request, self.query_url)
74+
75+
expected_headers_property = ' headers="date request-line"'
76+
expected_signature = TestUtil.create_signature(self.date_header, "",
77+
self.query_url, 'GET', True)
78+
self.assert_auth_header(request, expected_headers_property, expected_signature)
79+
80+
def assert_auth_header(self, request, expected_headers_property, expected_signature):
81+
username, algorithm, headers, signature = request.headers['Authorization'].split(',')
82+
with self.subTest():
83+
self.assertEqual(self.expected_username, username)
84+
self.assertEqual(expected_headers_property, headers)
85+
self.assertEqual(self.expected_algorithm, algorithm)
86+
self.assertEqual(expected_signature, signature)
87+
88+
@staticmethod
89+
def get_send_message_request():
90+
send_message_request = SendMessagesRequest()
91+
send_message_request.messages = []
92+
send_message_request.messages.append(Message())
93+
send_message_request.messages[0].content = 'My tests message'
94+
send_message_request.messages[0].destination_number = '+61491570006'
95+
send_message_request.messages[0].format = FormatEnum.SMS
96+
return send_message_request
97+
98+
@staticmethod
99+
def get_content_hash(request):
100+
m = hashlib.md5()
101+
m.update(bytes(APIHelper.json_serialize(request), 'utf-8'))
102+
content_hash = m.hexdigest()
103+
return content_hash

0 commit comments

Comments
 (0)