Skip to content

Commit ad2ec7d

Browse files
authored
Merge pull request #5 from Mastercard/feature/header_fix
Encryption params header fix
2 parents ad7005b + 81b5aad commit ad2ec7d

File tree

4 files changed

+40
-27
lines changed

4 files changed

+40
-27
lines changed

README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
This is the Python version of the Mastercard compliant payload encryption/decryption.
2323

2424
### Compatibility <a name="compatibility"></a>
25-
Python 3.6, 3.7
25+
Python 3.6+
2626

2727
### References <a name="references"></a>
2828

@@ -125,11 +125,13 @@ decrypted_response_payload = decrypt_payload(body, config)
125125

126126
The above can be either stored to a file or passed to 'FieldLevelEncryptionConfig' as dictionary:
127127
```python
128-
config_dictionary = {"paths": {...},
129-
(...)
130-
"decryptionKey": "./path/to/your/private.key",
131-
"oaepPaddingDigestAlgorithm": "SHA256"
128+
config_dictionary = {
129+
"paths": {...},
130+
(...)
131+
"decryptionKey": "./path/to/your/private.key",
132+
"oaepPaddingDigestAlgorithm": "SHA256"
132133
}
134+
133135
config = FieldLevelEncryptionConfig(config_dictionary)
134136

135137
config_file_path = "./config.json"
@@ -263,7 +265,7 @@ This method will add the field level encryption in the generated OpenApi client,
263265

264266
##### OpenAPI Generator <a name="openapi-generator"></a>
265267

266-
OpenAPI client can be generated, starting from your OpenAPI Spec / Swagger using the following command:
268+
OpenAPI client can be generated, starting from your OpenAPI Spec using the following command:
267269

268270
```shell
269271
java -jar openapi-generator-cli.jar generate -i openapi-spec.yaml -l python -o out
@@ -281,11 +283,11 @@ To use it:
281283

282284
1. Generate the [OpenAPI client](#openapi-generator)
283285

284-
2. Import the **mastercard-client-encryption** module and the generated swagger ApiClient
286+
2. Import the **mastercard-client-encryption** module and the generated OpenAPI client
285287

286288
```python
287289
from client_encryption.api_encryption import add_encryption_layer
288-
from swagger_client.api_client import ApiClient # import generated swagger ApiClient
290+
from openapi_client.api_client import ApiClient # import generated OpenAPI client
289291
```
290292

291293
3. Add the field level encryption layer to the generated client:
@@ -319,12 +321,12 @@ According to the above the signing layer must be applied first in order to work
319321

320322
1. Generate the [OpenAPI client](#openapi-generator)
321323

322-
2. Import both **mastercard-oauth1-signer** and **mastercard-client-encryption** modules and the generated swagger ApiClient
324+
2. Import both **mastercard-oauth1-signer** and **mastercard-client-encryption** modules and the generated OpenAPI client
323325

324326
```python
325327
from oauth1.signer_interceptor import add_signing_layer
326328
from client_encryption.api_encryption import add_encryption_layer
327-
from swagger_client.api_client import ApiClient # import generated swagger ApiClient
329+
from openapi_client.api_client import ApiClient # import generated OpenAPI client
328330
```
329331

330332
3. Add the authentication layer to the generated client:

client_encryption/api_encryption.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def call_api_function(*args, **kwargs):
2525
"""Wrap call_api and add field encryption layer to it."""
2626

2727
in_body = kwargs.get("body", None)
28-
kwargs["body"] = self._encrypt_payload(kwargs.get("header_params", None), in_body) if in_body else in_body
28+
kwargs["body"] = self._encrypt_payload(args[4], in_body) if in_body else in_body
2929
kwargs["_preload_content"] = False
3030

3131
response = func(*args, **kwargs)
@@ -44,13 +44,20 @@ def _encrypt_payload(self, headers, body):
4444
if conf.use_http_headers:
4545
params = SessionKeyParams.generate(conf)
4646

47-
headers[conf.iv_field_name] = params.iv_value
48-
headers[conf.encrypted_key_field_name] = params.encrypted_key_value
49-
headers[conf.encryption_certificate_fingerprint_field_name] = conf.encryption_certificate_fingerprint
50-
headers[conf.encryption_key_fingerprint_field_name] = conf.encryption_key_fingerprint
51-
headers[conf.oaep_padding_digest_algorithm_field_name] = conf.oaep_padding_digest_algorithm
47+
encryption_params = {
48+
conf.iv_field_name: params.iv_value,
49+
conf.encrypted_key_field_name: params.encrypted_key_value
50+
}
51+
if conf.encryption_certificate_fingerprint_field_name:
52+
encryption_params[conf.encryption_certificate_fingerprint_field_name] = \
53+
conf.encryption_certificate_fingerprint
54+
if conf.encryption_key_fingerprint_field_name:
55+
encryption_params[conf.encryption_key_fingerprint_field_name] = conf.encryption_key_fingerprint
56+
if conf.oaep_padding_digest_algorithm_field_name:
57+
encryption_params[conf.oaep_padding_digest_algorithm_field_name] = conf.oaep_padding_digest_algorithm
5258

5359
encrypted_payload = encrypt_payload(body, conf, params)
60+
headers.update(encryption_params)
5461
else:
5562
encrypted_payload = encrypt_payload(body, conf)
5663

@@ -67,10 +74,10 @@ def _decrypt_payload(self, headers, body):
6774
iv = headers.pop(conf.iv_field_name)
6875
encrypted_key = headers.pop(conf.encrypted_key_field_name)
6976
oaep_digest_algo = headers.pop(conf.oaep_padding_digest_algorithm_field_name) \
70-
if conf.oaep_padding_digest_algorithm_field_name in headers else None
71-
if conf.encryption_certificate_fingerprint_field_name in headers:
77+
if _contains_param(conf.oaep_padding_digest_algorithm_field_name, headers) else None
78+
if _contains_param(conf.encryption_certificate_fingerprint_field_name, headers):
7279
del headers[conf.encryption_certificate_fingerprint_field_name]
73-
if conf.encryption_key_fingerprint_field_name in headers:
80+
if _contains_param(conf.encryption_key_fingerprint_field_name, headers):
7481
del headers[conf.encryption_key_fingerprint_field_name]
7582

7683
params = SessionKeyParams(conf, encrypted_key, iv, oaep_digest_algo)
@@ -84,6 +91,9 @@ def _decrypt_payload(self, headers, body):
8491
return payload
8592

8693

94+
def _contains_param(param_name, headers): return param_name and param_name in headers
95+
96+
8797
def add_encryption_layer(api_client, encryption_conf_file):
8898
"""Decorate APIClient.call_api with field level encryption"""
8999

setup.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@
66
python_requires='>=3.5.4',
77
version=__version__,
88
description='Mastercard Client encryption.',
9-
long_description='Library for encrypting a Mastercard API compliant request.',
9+
long_description='Library for Mastercard API compliant payload encryption/decryption.',
1010
author='Mastercard',
1111
url='https://github.com/Mastercard/client-encryption-python',
1212
license='MIT',
1313
packages=['client_encryption'],
1414
classifiers=[
15-
'Development Status :: 4 - Beta',
15+
'Development Status :: 5 - Production/Stable',
1616
'Intended Audience :: Developers',
1717
'Natural Language :: English',
1818
'Operating System :: OS Independent',
1919
'Programming Language :: Python :: 3.6',
2020
'Programming Language :: Python :: 3.7',
21+
'Programming Language :: Python :: 3.8',
2122
'Topic :: Software Development :: Libraries :: Python Modules'
2223
],
2324
tests_require=['coverage'],

tests/utils/api_encryption_test_utils.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,22 @@ def __init__(self, api_client=None):
2525
self.api_client = api_client
2626

2727
def do_something_get(self, **kwargs):
28-
return self.api_client.call_api("testservice", "GET", header_params=kwargs["headers"])
28+
return self.api_client.call_api("testservice", "GET", None, None, kwargs["headers"])
2929

3030
def do_something_post(self, **kwargs):
31-
return self.api_client.call_api("testservice", "POST", header_params=kwargs["headers"], body=kwargs["body"])
31+
return self.api_client.call_api("testservice", "POST", None, None, kwargs["headers"], body=kwargs["body"])
3232

3333
def do_something_delete(self, **kwargs):
34-
return self.api_client.call_api("testservice", "DELETE", header_params=kwargs["headers"], body=kwargs["body"])
34+
return self.api_client.call_api("testservice", "DELETE", None, None, kwargs["headers"], body=kwargs["body"])
3535

3636
def do_something_get_use_headers(self, **kwargs):
37-
return self.api_client.call_api("testservice/headers", "GET", header_params=kwargs["headers"])
37+
return self.api_client.call_api("testservice/headers", "GET", None, None, kwargs["headers"])
3838

3939
def do_something_post_use_headers(self, **kwargs):
40-
return self.api_client.call_api("testservice/headers", "POST", header_params=kwargs["headers"], body=kwargs["body"])
40+
return self.api_client.call_api("testservice/headers", "POST", None, None, kwargs["headers"], body=kwargs["body"])
4141

4242
def do_something_delete_use_headers(self, **kwargs):
43-
return self.api_client.call_api("testservice/headers", "DELETE", header_params=kwargs["headers"], body=kwargs["body"])
43+
return self.api_client.call_api("testservice/headers", "DELETE", None, None, kwargs["headers"], body=kwargs["body"])
4444

4545

4646
class MockApiClient(object):

0 commit comments

Comments
 (0)