Skip to content

Commit 0892864

Browse files
m
1 parent 321284c commit 0892864

File tree

25 files changed

+2358
-52
lines changed

25 files changed

+2358
-52
lines changed

DynamoDbEncryption/runtimes/python/src/aws_database_encryption_sdk/internal/boto3_conversions.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
from abc import ABC, abstractmethod
2+
from boto3.dynamodb.conditions import (
3+
BuiltConditionExpression,
4+
)
25

36
class BotoInterfaceShapeConverter(ABC):
47
"""

DynamoDbEncryption/runtimes/python/src/aws_database_encryption_sdk/internal/condition_expression_builder.py

Lines changed: 258 additions & 46 deletions
Large diffs are not rendered by default.

DynamoDbEncryption/runtimes/python/src/aws_database_encryption_sdk/internal/resource_to_client.py

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
from aws_database_encryption_sdk.transform import dict_to_ddb
22
from .boto3_conversions import BotoInterfaceShapeConverter
33
from aws_database_encryption_sdk.internal.condition_expression_builder import InternalDBESDKDynamoDBConditionExpressionBuilder
4-
from boto3.dynamodb.conditions import ConditionBase
4+
from boto3.dynamodb.conditions import ConditionBase, BuiltConditionExpression
55

66
class ResourceShapeToClientShapeConverter(BotoInterfaceShapeConverter):
77

88
def __init__(self, table_name = None):
99
self.table_name = table_name
1010
self.expression_builder = InternalDBESDKDynamoDBConditionExpressionBuilder()
1111

12+
def _unpack_built_condition_expression(self, request_to_update, expression_key):
13+
built_condition_expression = request_to_update[expression_key]
14+
request_to_update[expression_key] = built_condition_expression.condition_expression
15+
attribute_names_from_built_expression = built_condition_expression.attribute_name_placeholders
16+
# Join any placeholder ExpressionAttributeNames with any other ExpressionAttributeNames
17+
try:
18+
request_to_update["ExpressionAttributeNames"] = request_to_update["ExpressionAttributeNames"] | attribute_names_from_built_expression
19+
except KeyError:
20+
request_to_update["ExpressionAttributeNames"] = attribute_names_from_built_expression
21+
# BuiltConditionExpression stores values in resource format; convert to client format before joining
22+
attribute_values_from_built_expression = super().expression_attribute_values(
23+
built_condition_expression.attribute_value_placeholders
24+
)
25+
try:
26+
request_to_update["ExpressionAttributeValues"] = request_to_update["ExpressionAttributeValues"] | attribute_values_from_built_expression
27+
except KeyError:
28+
request_to_update["ExpressionAttributeValues"] = attribute_values_from_built_expression
29+
1230
def item(self, item):
1331
return dict_to_ddb(item)
1432

@@ -23,7 +41,10 @@ def put_item_request(self, put_item_request):
2341
if not self.table_name:
2442
raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use put_item")
2543
put_item_request["TableName"] = self.table_name
26-
return super().put_item_request(put_item_request)
44+
super_conversion = super().put_item_request(put_item_request)
45+
if "ConditionExpression" in super_conversion and isinstance(super_conversion["ConditionExpression"], BuiltConditionExpression):
46+
self._unpack_built_condition_expression(super_conversion, "ConditionExpression")
47+
return super_conversion
2748

2849
def get_item_request(self, get_item_request):
2950
if not self.table_name:
@@ -35,18 +56,30 @@ def query_request(self, query_request):
3556
if not self.table_name:
3657
raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use query")
3758
query_request["TableName"] = self.table_name
38-
return super().query_request(query_request)
59+
super_conversion = super().query_request(query_request)
60+
if "KeyConditionExpression" in super_conversion and isinstance(super_conversion["KeyConditionExpression"], BuiltConditionExpression):
61+
self._unpack_built_condition_expression(super_conversion, "KeyConditionExpression")
62+
if "FilterExpression" in super_conversion and isinstance(super_conversion["FilterExpression"], BuiltConditionExpression):
63+
self._unpack_built_condition_expression(super_conversion, "FilterExpression")
64+
return super_conversion
3965

4066
def scan_request(self, scan_request):
4167
if not self.table_name:
4268
raise ValueError("Table name must be provided to ResourceShapeToClientShapeConverter to use scan")
4369
scan_request["TableName"] = self.table_name
44-
return super().scan_request(scan_request)
70+
super_conversion = super().scan_request(scan_request)
71+
if "FilterExpression" in super_conversion and isinstance(super_conversion["FilterExpression"], BuiltConditionExpression):
72+
self._unpack_built_condition_expression(super_conversion, "FilterExpression")
73+
return super_conversion
4574

4675
def expression(self, condition_expression):
4776
# Expressions provided to tables can be Condition objects, which need to be converted to strings.
48-
if isinstance(condition_expression, ConditionBase):
49-
return self.expression_builder.build_expression(condition_expression, "placeholder", "placeholder")
77+
if condition_expression.__module__ == "boto3.dynamodb.conditions":
78+
out = self.expression_builder.build_expression(condition_expression, {}, {})
79+
print(f"{condition_expression=}")
80+
print(f"{out=}")
81+
return out
5082
# Expressions provided to tables can also already be string-like.
5183
# Assume the user has provided something string-like, and let Smithy-Python/DBESDK internals raise exceptions if not.
84+
print(f"probably a string: {condition_expression=}")
5285
return condition_expression
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from aws_cryptographic_material_providers.keystore.models import (
2+
KMSConfigurationKmsKeyArn,
3+
CreateKeyInput,
4+
)
5+
import boto3
6+
from aws_cryptographic_material_providers.keystore.client import KeyStore
7+
from aws_cryptographic_material_providers.keystore.config import KeyStoreConfig
8+
9+
"""
10+
The Hierarchical Keyring Example and Searchable Encryption Examples
11+
rely on the existence of a DDB-backed key store with pre-existing
12+
branch key material or beacon key material.
13+
14+
See the "Create KeyStore Table Example" for how to first set up
15+
the DDB Table that will back this KeyStore.
16+
17+
This example demonstrates configuring a KeyStore and then
18+
using a helper method to create a branch key and beacon key
19+
that share the same Id, then return that Id.
20+
We will always create a new beacon key alongside a new branch key,
21+
even if you are not using searchable encryption.
22+
23+
This key creation should occur within your control plane.
24+
"""
25+
26+
def keystore_create_key(key_store_table_name: str,
27+
logical_key_store_name: str,
28+
kms_key_arn: str) -> str:
29+
# 1. Configure your KeyStore resource.
30+
# This SHOULD be the same configuration that was used to create the DDB table
31+
# in the "Create KeyStore Table Example".
32+
keystore: KeyStore = KeyStore(
33+
KeyStoreConfig(
34+
ddb_table_name = key_store_table_name,
35+
kms_configuration=KMSConfigurationKmsKeyArn(
36+
kms_key_arn
37+
),
38+
logical_key_store_name=logical_key_store_name,
39+
kms_client=boto3.client("kms"),
40+
ddb_client=boto3.client("dynamodb")
41+
)
42+
)
43+
44+
# 2. Create a new branch key and beacon key in our KeyStore.
45+
# Both the branch key and the beacon key will share an Id.
46+
# This creation is eventually consistent.
47+
branch_key_id = keystore.create_key(
48+
CreateKeyInput()
49+
).branch_key_identifier
50+
51+
print(f"{branch_key_id=}")
52+
53+
return branch_key_id
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0

0 commit comments

Comments
 (0)