Skip to content

Commit 998575c

Browse files
authored
Merge head of master into keyring (#195)
* Update PR template * Added a check for max_age being greater than 0 (#172) * Added a check for max_age being greater than 0 * Fixed flake8 by adding missing pydocstyle dependency * Added the dependency to decrypt_oracle as well * Added test for max_age<=0 ValueError * Updated test for max_age<=0.0 ValueError * Added negative test case * Fixed KMS master key provider tests when default AWS region is configured (#179) * Fixed KMS master key provider tests for users who have their default AWS region configured * created fixture for botocore session with no region set * add auto-used fixture in KMS master key provider unit tests to test against both with and without default region * Wrote example and test for using one kms cmk with an unsigned algorithm * Update one_kms_cmk_unsigned.py * Update examples/src/one_kms_cmk_unsigned.py Co-Authored-By: Matt Bullock <[email protected]> * isort-check now succeeds * [issue-190] Regional clients modify default botocore session (#193) * [issue-190] Creation of regional clients modifies default botocore session's region * update changelog with changes for 1.4.1 release * bump version to 1.4.1 * Updates to handle new pylint requirements (#196) * pylint max-attributes appears to be ratcheted down recently * remove unnecessary comprehensions * whitelist some pylint use-constant-test false-positives * reorganize backwards compatibility test requirements definitions attrs==19.2.0 removed a deprecated feature that aws-encryption-sdk==1.3.3 depended on. This reorganization lets us define specific requirements bounds for old versions of aws-encryption-sdk that will probably continue to be necessary as these old versions age. * remove unnecessary comprehensions * add newlines to the end of all requirements files * help pylint ignore mypy type use
1 parent 2e85bfd commit 998575c

32 files changed

+208
-35
lines changed

.github/PULL_REQUEST_TEMPLATE.md

+4
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44

55

66
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
7+
8+
# Check any applicable:
9+
- [ ] Were any files moved? Moving files changes their URL, which breaks all hyperlinks to the files.
10+

CHANGELOG.rst

+17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,23 @@
22
Changelog
33
*********
44

5+
1.4.1 -- 2019-09-20
6+
===================
7+
8+
Bugfixes
9+
--------
10+
11+
* Fix region configuration override in botocore sessions.
12+
`#190 <https://github.com/aws/aws-encryption-sdk-python/issues/190>`_
13+
`#193 <https://github.com/aws/aws-encryption-sdk-python/pull/193>`_
14+
15+
Minor
16+
-----
17+
18+
* Caching CMM must require that max age configuration value is greater than 0.
19+
`#147 <https://github.com/aws/aws-encryption-sdk-python/issues/147>`_
20+
`#172 <https://github.com/aws/aws-encryption-sdk-python/pull/172>`_
21+
522
1.4.0 -- 2019-05-23
623
===================
724

decrypt_oracle/setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def get_version():
2222
def get_requirements():
2323
"""Read the requirements file."""
2424
requirements = read("requirements-actual.txt")
25-
return [r for r in requirements.strip().splitlines()]
25+
return list(requirements.strip().splitlines())
2626

2727

2828
setup(

decrypt_oracle/tox.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ basepython = python3
156156
deps =
157157
flake8
158158
flake8-docstrings
159-
pydocstyle < 4.0.0
159+
pydocstyle<4.0.0
160160
# https://github.com/JBKahn/flake8-print/pull/30
161161
flake8-print>=3.1.0
162162
commands =

doc/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
sphinx>=1.3.0
2-
sphinx_rtd_theme
2+
sphinx_rtd_theme

examples/src/one_kms_cmk_unsigned.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
"""Example showing basic encryption and decryption of a value already in memory
14+
using one KMS CMK with an unsigned algorithm.
15+
"""
16+
from aws_encryption_sdk import KMSMasterKeyProvider, decrypt, encrypt
17+
from aws_encryption_sdk.identifiers import Algorithm
18+
19+
20+
def encrypt_decrypt(key_arn, source_plaintext, botocore_session=None):
21+
"""Encrypts and then decrypts a string under one KMS customer master key (CMK) with an unsigned algorithm.
22+
23+
:param str key_arn: Amazon Resource Name (ARN) of the KMS CMK
24+
:param bytes source_plaintext: Data to encrypt
25+
:param botocore_session: existing botocore session instance
26+
:type botocore_session: botocore.session.Session
27+
"""
28+
kwargs = dict(key_ids=[key_arn])
29+
30+
if botocore_session is not None:
31+
kwargs["botocore_session"] = botocore_session
32+
33+
# Create master key provider using the ARN of the key and the session (botocore_session)
34+
kms_key_provider = KMSMasterKeyProvider(**kwargs)
35+
36+
# Encrypt the plaintext using the AWS Encryption SDK. It returns the encrypted message and the header
37+
ciphertext, encrypted_message_header = encrypt(
38+
algorithm=Algorithm.AES_256_GCM_IV12_TAG16_HKDF_SHA256, source=source_plaintext, key_provider=kms_key_provider
39+
)
40+
41+
# Decrypt the encrypted message using the AWS Encryption SDK. It returns the decrypted message and the header
42+
plaintext, decrypted_message_header = decrypt(source=ciphertext, key_provider=kms_key_provider)
43+
44+
# Check if the original message and the decrypted message are the same
45+
assert source_plaintext == plaintext
46+
47+
# Check if the headers of the encrypted message and decrypted message match
48+
assert all(
49+
pair in encrypted_message_header.encryption_context.items()
50+
for pair in decrypted_message_header.encryption_context.items()
51+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
"""Unit test suite for the encryption and decryption using one KMS CMK with an unsigned algorithm example."""
14+
15+
import botocore.session
16+
import pytest
17+
18+
from ..src.one_kms_cmk_unsigned import encrypt_decrypt
19+
from .examples_test_utils import get_cmk_arn
20+
from .examples_test_utils import static_plaintext
21+
22+
23+
pytestmark = [pytest.mark.examples]
24+
25+
26+
def test_one_kms_cmk_unsigned():
27+
plaintext = static_plaintext
28+
cmk_arn = get_cmk_arn()
29+
encrypt_decrypt(key_arn=cmk_arn, source_plaintext=plaintext, botocore_session=botocore.session.Session())

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ six
22
boto3>=1.4.4
33
cryptography>=1.8.1
44
attrs>=19.1.0
5-
wrapt>=1.10.11
5+
wrapt>=1.10.11

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def get_version():
2222
def get_requirements():
2323
"""Reads the requirements file."""
2424
requirements = read("requirements.txt")
25-
return [r for r in requirements.strip().splitlines()]
25+
return list(requirements.strip().splitlines())
2626

2727

2828
setup(

src/aws_encryption_sdk/caches/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class CryptoMaterialsCacheEntryHints(object):
143143

144144
@attr.s(hash=False)
145145
class CryptoMaterialsCacheEntry(object):
146+
# pylint: disable=too-many-instance-attributes
146147
"""Value and metadata store for cryptographic materials cache entries.
147148
148149
:param bytes cache_key: Identifier for entries in cache

src/aws_encryption_sdk/identifiers.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# We only actually need these imports when running the mypy checks
2828
pass
2929

30-
__version__ = "1.4.0"
30+
__version__ = "1.4.1"
3131
USER_AGENT_SUFFIX = "AwsEncryptionSdkPython/{}".format(__version__)
3232

3333

src/aws_encryption_sdk/key_providers/kms.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ def add_regional_client(self, region_name):
161161
:param str region_name: AWS Region ID (ex: us-east-1)
162162
"""
163163
if region_name not in self._regional_clients:
164-
session = boto3.session.Session(region_name=region_name, botocore_session=self.config.botocore_session)
165-
client = session.client("kms", config=self._user_agent_adding_config)
164+
session = boto3.session.Session(botocore_session=self.config.botocore_session)
165+
client = session.client("kms", region_name=region_name, config=self._user_agent_adding_config)
166166
self._register_client(client, region_name)
167167
self._regional_clients[region_name] = client
168168

src/aws_encryption_sdk/keyring/base.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111
# ANY KIND, either express or implied. See the License for the specific
1212
# language governing permissions and limitations under the License.
1313
"""Base class interface for Keyrings."""
14-
from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials
15-
from aws_encryption_sdk.structures import EncryptedDataKey
14+
from aws_encryption_sdk.materials_managers import ( # only used for mypy; pylint: disable=unused-import,duplicate-code
15+
DecryptionMaterials,
16+
EncryptionMaterials,
17+
)
18+
from aws_encryption_sdk.structures import ( # only used for mypy; pylint: disable=unused-import,duplicate-code
19+
EncryptedDataKey,
20+
)
1621

1722
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
1823
from typing import Iterable # noqa pylint: disable=unused-import

src/aws_encryption_sdk/keyring/multi_keyring.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
from attr.validators import deep_iterable, instance_of, optional
1818

1919
from aws_encryption_sdk.exceptions import EncryptKeyError, GenerateKeyError
20-
from aws_encryption_sdk.keyring.base import DecryptionMaterials, EncryptedDataKey, EncryptionMaterials, Keyring
20+
from aws_encryption_sdk.keyring.base import DecryptionMaterials # only used for mypy so pylint: disable=unused-import
21+
from aws_encryption_sdk.keyring.base import EncryptionMaterials # only used for mypy so pylint: disable=unused-import
22+
from aws_encryption_sdk.keyring.base import Keyring
23+
from aws_encryption_sdk.structures import EncryptedDataKey # only used for mypy so pylint: disable=unused-import
2124

2225
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
2326
from typing import Iterable # noqa pylint: disable=unused-import

src/aws_encryption_sdk/keyring/raw_keyring.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,12 @@
2929
from aws_encryption_sdk.internal.formatting.serialize import serialize_raw_master_key_prefix, serialize_wrapped_key
3030
from aws_encryption_sdk.key_providers.raw import RawMasterKey
3131
from aws_encryption_sdk.keyring.base import Keyring
32-
from aws_encryption_sdk.materials_managers import DecryptionMaterials, EncryptionMaterials
33-
from aws_encryption_sdk.structures import EncryptedDataKey, KeyringTrace, MasterKeyInfo, RawDataKey
32+
from aws_encryption_sdk.materials_managers import ( # only used for mypy so pylint: disable=unused-import
33+
DecryptionMaterials,
34+
EncryptionMaterials,
35+
)
36+
from aws_encryption_sdk.structures import EncryptedDataKey # only used for mypy so pylint: disable=unused-import
37+
from aws_encryption_sdk.structures import KeyringTrace, MasterKeyInfo, RawDataKey
3438

3539
try: # Python 3.5.0 and 3.5.1 have incompatible typing modules
3640
from typing import Iterable # noqa pylint: disable=unused-import

src/aws_encryption_sdk/materials_managers/caching.py

+3
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ def __attrs_post_init__(self):
108108
if self.max_bytes_encrypted > MAX_BYTES_PER_KEY:
109109
raise ValueError("max_bytes_encrypted cannot exceed {}".format(MAX_BYTES_PER_KEY))
110110

111+
if self.max_age <= 0.0:
112+
raise ValueError("max_age cannot be less than or equal to 0")
113+
111114
if self.backing_materials_manager is None:
112115
if self.master_key_provider is None:
113116
raise TypeError("Either backing_materials_manager or master_key_provider must be defined")

src/aws_encryption_sdk/streaming_client.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ def read(self, b=-1):
235235
if not self._message_prepped:
236236
self._prep_message()
237237

238-
if self.closed:
238+
if self.closed: # dynamic values confuse pylint: disable=using-constant-test
239239
raise ValueError("I/O operation on closed file")
240240

241241
if b >= 0:
@@ -283,7 +283,7 @@ def readline(self):
283283

284284
def readlines(self):
285285
"""Reads all chunks of output, outputting a list as defined in the IOBase specification."""
286-
return [line for line in self]
286+
return list(self)
287287

288288
def __iter__(self):
289289
"""Make this class and subclasses identify as iterators."""
@@ -292,7 +292,7 @@ def __iter__(self):
292292
def next(self):
293293
"""Provides hook for Python2 iterator functionality."""
294294
_LOGGER.debug("reading next")
295-
if self.closed:
295+
if self.closed: # dynamic values confuse pylint: disable=using-constant-test
296296
_LOGGER.debug("stream is closed")
297297
raise StopIteration()
298298

src/aws_encryption_sdk/structures.py

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class KeyringTrace(object):
117117

118118
@attr.s(hash=True)
119119
class MessageHeader(object):
120+
# pylint: disable=too-many-instance-attributes
120121
"""Deserialized message header object.
121122
122123
:param version: Message format version, per spec

test/integration/integration_test_utils.py

+19
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@
1313
"""Utility functions to handle configuration and credentials setup for integration tests."""
1414
import os
1515

16+
import botocore.session
17+
1618
from aws_encryption_sdk.key_providers.kms import KMSMasterKeyProvider
1719

1820
AWS_KMS_KEY_ID = "AWS_ENCRYPTION_SDK_PYTHON_INTEGRATION_TEST_AWS_KMS_KEY_ID"
1921
_KMS_MKP = None
22+
_KMS_MKP_BOTO = None
2023

2124

2225
def get_cmk_arn():
@@ -47,3 +50,19 @@ def setup_kms_master_key_provider(cache=True):
4750
_KMS_MKP = kms_master_key_provider
4851

4952
return kms_master_key_provider
53+
54+
55+
def setup_kms_master_key_provider_with_botocore_session(cache=True):
56+
"""Reads the test_values config file and builds the requested KMS Master Key Provider with botocore_session."""
57+
global _KMS_MKP_BOTO # pylint: disable=global-statement
58+
if cache and _KMS_MKP_BOTO is not None:
59+
return _KMS_MKP_BOTO
60+
61+
cmk_arn = get_cmk_arn()
62+
kms_master_key_provider = KMSMasterKeyProvider(botocore_session=botocore.session.Session())
63+
kms_master_key_provider.add_master_key(cmk_arn)
64+
65+
if cache:
66+
_KMS_MKP_BOTO = kms_master_key_provider
67+
68+
return kms_master_key_provider

test/integration/test_i_aws_encrytion_sdk_client.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
from aws_encryption_sdk.identifiers import USER_AGENT_SUFFIX, Algorithm
2222
from aws_encryption_sdk.key_providers.kms import KMSMasterKey, KMSMasterKeyProvider
2323

24-
from .integration_test_utils import get_cmk_arn, setup_kms_master_key_provider
24+
from .integration_test_utils import (
25+
get_cmk_arn,
26+
setup_kms_master_key_provider,
27+
setup_kms_master_key_provider_with_botocore_session,
28+
)
2529

2630
pytestmark = [pytest.mark.integ]
2731

@@ -68,6 +72,15 @@ def test_remove_bad_client():
6872
assert not test._regional_clients
6973

7074

75+
def test_regional_client_does_not_modify_botocore_session(caplog):
76+
mkp = setup_kms_master_key_provider_with_botocore_session()
77+
fake_region = "us-fakey-12"
78+
79+
assert mkp.config.botocore_session.get_config_variable("region") != fake_region
80+
mkp.add_regional_client(fake_region)
81+
assert mkp.config.botocore_session.get_config_variable("region") != fake_region
82+
83+
7184
class TestKMSThickClientIntegration(object):
7285
@pytest.fixture(autouse=True)
7386
def apply_fixtures(self):

test/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
mock
22
pytest>=3.3.1
33
pytest-cov
4-
pytest-mock
4+
pytest-mock

test/unit/test_identifiers.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def test_algorithm_safe_to_cache(check_algorithm, safe_to_cache):
4141
assert not check_algorithm.safe_to_cache()
4242

4343

44-
@pytest.mark.parametrize("suite", [suite for suite in EncryptionSuite])
44+
@pytest.mark.parametrize("suite", list(EncryptionSuite))
4545
def test_encryption_suite_invalid_kdf(suite):
4646
mock_kdf = Mock()
4747
mock_kdf.input_length.return_value = 1

test/unit/test_material_managers_caching.py

+2
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ def test_mkp_to_default_cmm(mocker):
117117
dict(max_bytes_encrypted=MAX_BYTES_PER_KEY + 1),
118118
r"max_bytes_encrypted cannot exceed {}".format(MAX_BYTES_PER_KEY),
119119
),
120+
(dict(max_age=0.0), r"max_age cannot be less than or equal to 0"),
121+
(dict(max_age=-1.0), r"max_age cannot be less than or equal to 0"),
120122
),
121123
)
122124
def test_invalid_values(invalid_kwargs, error_message):

0 commit comments

Comments
 (0)