diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryption/Model/DynamoDbEncryption.smithy b/DynamoDbEncryption/dafny/DynamoDbEncryption/Model/DynamoDbEncryption.smithy index defdeba7f..fe7cc927e 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryption/Model/DynamoDbEncryption.smithy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryption/Model/DynamoDbEncryption.smithy @@ -653,7 +653,7 @@ structure BeaconVersion { @javadoc("The version of searchable encryption configured. This must be '1'.") version : VersionNumber, @required - @javadoc("The Key Store that contains the Becon Keys to use with searchable encryption.") + @javadoc("The Key Store that contains the Beacon Keys to use with searchable encryption.") keyStore : KeyStoreReference, @required @javadoc("The configuration for what beacon key(s) to use.") diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryption/src/DDBSupport.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryption/src/DDBSupport.dfy index 05088cada..65a299690 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryption/src/DDBSupport.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryption/src/DDBSupport.dfy @@ -331,4 +331,63 @@ module DynamoDBSupport { return Success(resp.(Items := Some(trimmedItems), Count := count)); } } + + function method {:tailrecursion} GetVirtualFieldsLoop( + fields : seq, + bv : SearchableEncryptionInfo.BeaconVersion, + item : DDB.AttributeMap, + results : map := map[]) + : (output : Result, Error>) + requires forall x <- fields :: x in bv.virtualFields + requires forall x <- results :: x in bv.virtualFields + ensures output.Success? ==> forall x <- output.value :: x in bv.virtualFields + { + if |fields| == 0 then + Success(results) + else + var optValue :- GetVirtField(bv.virtualFields[fields[0]], item); + if optValue.Some? then + GetVirtualFieldsLoop(fields[1..], bv, item, results[fields[0] := optValue.value]) + else + GetVirtualFieldsLoop(fields[1..], bv, item, results) + } + + method GetVirtualFields(beaconVersion : SearchableEncryptionInfo.BeaconVersion, item : DDB.AttributeMap) + returns (output : Result, Error>) + { + var fieldNames := SortedSets.ComputeSetToOrderedSequence2(beaconVersion.virtualFields.Keys, CharLess); + output := GetVirtualFieldsLoop(fieldNames, beaconVersion, item); + } + + function method {:tailrecursion} GetCompoundBeaconsLoop( + fields : seq, + bv : SearchableEncryptionInfo.BeaconVersion, + item : DDB.AttributeMap, + results : map := map[]) + : (output : Result, Error>) + requires forall x <- fields :: x in bv.beacons + requires forall x <- results :: x in bv.beacons + ensures output.Success? ==> forall x <- output.value :: x in bv.beacons + { + if |fields| == 0 then + Success(results) + else + var beacon := bv.beacons[fields[0]]; + if beacon.Compound? then + var optValue :- beacon.cmp.getNaked(item, bv.virtualFields); + if optValue.Some? then + GetCompoundBeaconsLoop(fields[1..], bv, item, results[fields[0] := optValue.value]) + else + GetCompoundBeaconsLoop(fields[1..], bv, item, results) + else + GetCompoundBeaconsLoop(fields[1..], bv, item, results) + } + + method GetCompoundBeacons(beaconVersion : SearchableEncryptionInfo.BeaconVersion, item : DDB.AttributeMap) + returns (output : Result, Error>) + { + var beaconNames := SortedSets.ComputeSetToOrderedSequence2(beaconVersion.beacons.Keys, CharLess); + output := GetCompoundBeaconsLoop(beaconNames, beaconVersion, item); + } + } diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Virtual.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Virtual.dfy index 7982eeca2..bdcf851a8 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Virtual.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryption/src/Virtual.dfy @@ -393,38 +393,10 @@ module DdbVirtualFields { TermLoc.TermToString(loc, item) } - /* - // return true if item has all of the terminals necessary for field - predicate method ValueHasNeededAttrs(field : VirtualField, item : DDB.AttributeMap) - { - !field.examine(t => LacksAttribute(t, item)) - } -*/ // convert string to DynamoDB Attribute function method DS(s : string) : DDB.AttributeValue { DDB.AttributeValue.S(s) } - /* - // return an AttributeMap containing all of the virtual fields for which we have the appropriate attributes - function method {:tailrecursion} GetVirtualAttrs ( - fields : seq, - item : DDB.AttributeMap, - acc : DDB.AttributeMap := map[]) - : (ret : Result) - requires AllStrings(acc) - ensures ret.Success? ==> AllStrings(ret.value) - { - if |fields| == 0 then - Success(acc) - else - :- Need(DDB.IsValid_AttributeName(fields[0].name), "Virtual field name '" + fields[0].name + "' is not a valid DynamoDB Attribute Name"); - if ValueHasNeededAttrs(fields[0], item) then - var value :- fields[0].makeString(t => TermToString(t, item)); - GetVirtualAttrs(fields[1..], item, acc[fields[0].name := DDB.AttributeValue.S(value)]) - else - GetVirtualAttrs(fields[1..], item, acc) - } - */ } diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.dfy index 9a9d290dc..af0673b39 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes.dfy @@ -98,6 +98,7 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" BatchExecuteStatementOutputTransform := []; ExecuteTransactionInputTransform := []; ExecuteTransactionOutputTransform := []; + ResolveAttributes := []; } ghost var PutItemInputTransform: seq>> ghost var PutItemOutputTransform: seq>> @@ -125,6 +126,7 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" ghost var BatchExecuteStatementOutputTransform: seq>> ghost var ExecuteTransactionInputTransform: seq>> ghost var ExecuteTransactionOutputTransform: seq>> + ghost var ResolveAttributes: seq>> } trait {:termination false} IDynamoDbEncryptionTransformsClient { @@ -542,6 +544,22 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" && ValidState() ensures ExecuteTransactionOutputTransformEnsuresPublicly(input, output) ensures History.ExecuteTransactionOutputTransform == old(History.ExecuteTransactionOutputTransform) + [DafnyCallEvent(input, output)] + + predicate ResolveAttributesEnsuresPublicly(input: ResolveAttributesInput , output: Result) + // The public method to be called by library consumers + method ResolveAttributes ( input: ResolveAttributesInput ) + returns (output: Result) + requires + && ValidState() + modifies Modifies - {History} , + History`ResolveAttributes + // Dafny will skip type parameters when generating a default decreases clause. + decreases Modifies - {History} + ensures + && ValidState() + ensures ResolveAttributesEnsuresPublicly(input, output) + ensures History.ResolveAttributes == old(History.ResolveAttributes) + [DafnyCallEvent(input, output)] + } datatype ExecuteStatementInputTransformInput = | ExecuteStatementInputTransformInput ( nameonly sdkInput: ComAmazonawsDynamodbTypes.ExecuteStatementInput @@ -608,6 +626,15 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" datatype QueryOutputTransformOutput = | QueryOutputTransformOutput ( nameonly transformedOutput: ComAmazonawsDynamodbTypes.QueryOutput ) + datatype ResolveAttributesInput = | ResolveAttributesInput ( + nameonly TableName: ComAmazonawsDynamodbTypes.TableName , + nameonly Item: ComAmazonawsDynamodbTypes.AttributeMap , + nameonly Version: Option + ) + datatype ResolveAttributesOutput = | ResolveAttributesOutput ( + nameonly VirtualFields: StringMap , + nameonly CompoundBeacons: StringMap + ) datatype ScanInputTransformInput = | ScanInputTransformInput ( nameonly sdkInput: ComAmazonawsDynamodbTypes.ScanInput ) @@ -621,6 +648,7 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" datatype ScanOutputTransformOutput = | ScanOutputTransformOutput ( nameonly transformedOutput: ComAmazonawsDynamodbTypes.ScanOutput ) + type StringMap = map datatype TransactGetItemsInputTransformInput = | TransactGetItemsInputTransformInput ( nameonly sdkInput: ComAmazonawsDynamodbTypes.TransactGetItemsInput ) @@ -1357,6 +1385,27 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" output := Operations.ExecuteTransactionOutputTransform(config, input); History.ExecuteTransactionOutputTransform := History.ExecuteTransactionOutputTransform + [DafnyCallEvent(input, output)]; } + + predicate ResolveAttributesEnsuresPublicly(input: ResolveAttributesInput , output: Result) + {Operations.ResolveAttributesEnsuresPublicly(input, output)} + // The public method to be called by library consumers + method ResolveAttributes ( input: ResolveAttributesInput ) + returns (output: Result) + requires + && ValidState() + modifies Modifies - {History} , + History`ResolveAttributes + // Dafny will skip type parameters when generating a default decreases clause. + decreases Modifies - {History} + ensures + && ValidState() + ensures ResolveAttributesEnsuresPublicly(input, output) + ensures History.ResolveAttributes == old(History.ResolveAttributes) + [DafnyCallEvent(input, output)] + { + output := Operations.ResolveAttributes(config, input); + History.ResolveAttributes := History.ResolveAttributes + [DafnyCallEvent(input, output)]; +} + } } abstract module AbstractAwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations { @@ -1781,4 +1830,20 @@ include "../../../../submodules/MaterialProviders/StandardLibrary/src/Index.dfy" ensures && ValidInternalConfig?(config) ensures ExecuteTransactionOutputTransformEnsuresPublicly(input, output) + + + predicate ResolveAttributesEnsuresPublicly(input: ResolveAttributesInput , output: Result) + // The private method to be refined by the library developer + + + method ResolveAttributes ( config: InternalConfig , input: ResolveAttributesInput ) + returns (output: Result) + requires + && ValidInternalConfig?(config) + modifies ModifiesInternalConfig(config) + // Dafny will skip type parameters when generating a default decreases clause. + decreases ModifiesInternalConfig(config) + ensures + && ValidInternalConfig?(config) + ensures ResolveAttributesEnsuresPublicly(input, output) } diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/DynamoDbEncryptionTransforms.smithy b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/DynamoDbEncryptionTransforms.smithy index ff0f35739..8a5ee8974 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/DynamoDbEncryptionTransforms.smithy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/Model/DynamoDbEncryptionTransforms.smithy @@ -5,10 +5,15 @@ namespace aws.cryptography.dbEncryptionSdk.dynamoDb.transforms use aws.cryptography.dbEncryptionSdk.dynamoDb#DynamoDbTablesEncryptionConfig use com.amazonaws.dynamodb#DynamoDB_20120810 +use com.amazonaws.dynamodb#TableName +use com.amazonaws.dynamodb#AttributeMap + use aws.cryptography.dbEncryptionSdk.dynamoDb#DynamoDbEncryption use aws.cryptography.dbEncryptionSdk.dynamoDb.itemEncryptor#DynamoDbItemEncryptor +use aws.cryptography.dbEncryptionSdk.dynamoDb#VersionNumber use aws.polymorph#localService +use aws.polymorph#javadoc @localService( sdkId: "DynamoDbEncryptionTransforms", @@ -48,10 +53,43 @@ service DynamoDbEncryptionTransforms { BatchExecuteStatementOutputTransform, ExecuteTransactionInputTransform, ExecuteTransactionOutputTransform, + ResolveAttributes, ], errors: [ DynamoDbEncryptionTransformsException ] } +@javadoc("Given an Item, show the intermediate values (e.g. compound beacons, virtual fields).") +operation ResolveAttributes { + input: ResolveAttributesInput, + output: ResolveAttributesOutput, +} + +map StringMap { + key : String, + value : String +} + +structure ResolveAttributesInput { + @required + @javadoc("Use the config for this Table.") + TableName: TableName, + @required + @javadoc("The Item to be examined.") + Item: AttributeMap, + @javadoc("The beacon version to use. Defaults to 'writeVersion'.") + Version : VersionNumber +} + +structure ResolveAttributesOutput { + @required + @javadoc("Full plaintext of all calculable virtual fields.") + VirtualFields: StringMap, + @required + @javadoc("Full plaintext of all calculable compound beacons.") + CompoundBeacons: StringMap, +} + + @aws.polymorph#reference(service: aws.cryptography.dbEncryptionSdk.dynamoDb.itemEncryptor#DynamoDbItemEncryptor) structure DynamoDbItemEncryptorReference {} diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/AttributeResolver.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/AttributeResolver.dfy new file mode 100644 index 000000000..9a7a76ec8 --- /dev/null +++ b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/AttributeResolver.dfy @@ -0,0 +1,45 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +include "DynamoDbMiddlewareSupport.dfy" + +module AttributeResolver { + import opened DdbMiddlewareConfig + import opened DynamoDbMiddlewareSupport + import opened Wrappers + import DDB = ComAmazonawsDynamodbTypes + import opened AwsCryptographyDbEncryptionSdkDynamoDbTransformsTypes + import EncTypes = AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorTypes + import Seq + import DynamoDBSupport + + method Resolve(config: Config, input: ResolveAttributesInput) + returns (output: Result) + requires ValidConfig?(config) + ensures ValidConfig?(config) + modifies ModifiesConfig(config) + + { + if || input.TableName !in config.tableEncryptionConfigs + || config.tableEncryptionConfigs[input.TableName].search.None? + { + return Success( + ResolveAttributesOutput( + VirtualFields := map[], + CompoundBeacons := map[] + ) + ); + } else { + var tableConfig := config.tableEncryptionConfigs[input.TableName]; + var vf :- GetVirtualFields(tableConfig.search.value, input.Item, input.Version); + var cb :- GetCompoundBeacons(tableConfig.search.value, input.Item, input.Version); + return Success( + ResolveAttributesOutput( + VirtualFields := vf, + CompoundBeacons := cb + ) + ); + } + } + +} diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations.dfy index d0d3e6e32..4a1387911 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations.dfy @@ -16,6 +16,7 @@ include "DeleteItemTransform.dfy" include "ExecuteStatementTransform.dfy" include "BatchExecuteStatementTransform.dfy" include "ExecuteTransactionTransform.dfy" +include "AttributeResolver.dfy" module AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations refines AbstractAwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations { import opened DdbMiddlewareConfig @@ -41,6 +42,7 @@ module AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations refines Abstra import ExecuteStatementTransform import BatchExecuteStatementTransform import ExecuteTransactionTransform + import AttributeResolver predicate ValidInternalConfig?(config: InternalConfig) { @@ -288,4 +290,13 @@ module AwsCryptographyDbEncryptionSdkDynamoDbTransformsOperations refines Abstra { output := ExecuteTransactionTransform.Output(config, input); } + + predicate ResolveAttributesEnsuresPublicly(input: ResolveAttributesInput, output: Result) + {true} + + method ResolveAttributes(config: InternalConfig, input: ResolveAttributesInput) + returns (output: Result) + { + output := AttributeResolver.Resolve(config, input); + } } diff --git a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/DynamoDbMiddlewareSupport.dfy b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/DynamoDbMiddlewareSupport.dfy index ed85df9ab..7dadca820 100644 --- a/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/DynamoDbMiddlewareSupport.dfy +++ b/DynamoDbEncryption/dafny/DynamoDbEncryptionTransforms/src/DynamoDbMiddlewareSupport.dfy @@ -19,7 +19,9 @@ module DynamoDbMiddlewareSupport { import opened BS = DynamoDBSupport import opened DdbMiddlewareConfig import AwsCryptographyDbEncryptionSdkDynamoDbItemEncryptorOperations + import ET = AwsCryptographyDbEncryptionSdkDynamoDbTypes import Util = DynamoDbEncryptionUtil + import SI = SearchableEncryptionInfo // IsWritable examines an AttributeMap and fails if it is unsuitable for writing. // Generally this means that no attribute names starts with "aws_dbe_" @@ -202,4 +204,25 @@ module DynamoDbMiddlewareSupport { var ret := BS.ScanOutputForBeacons(config.search, req, resp); return ret.MapFailure(e => AwsCryptographyDbEncryptionSdkDynamoDb(e)); } + + method GetVirtualFields(search : SearchableEncryptionInfo.ValidSearchInfo, item : DDB.AttributeMap, version : Option) + returns (output : Result, Error>) + { + if version.Some? && version.value != 1 { + return Failure(E("Beacon Version Number must be '1'")); + } + var ret := BS.GetVirtualFields(search.curr(), item); + return ret.MapFailure(e => AwsCryptographyDbEncryptionSdkDynamoDb(e)); + } + + method GetCompoundBeacons(search : SearchableEncryptionInfo.ValidSearchInfo, item : DDB.AttributeMap, version : Option) + returns (output : Result, Error>) + { + if version.Some? && version.value != 1 { + return Failure(E("Beacon Version Number must be '1'")); + } + var ret := BS.GetCompoundBeacons(search.curr(), item); + return ret.MapFailure(e => AwsCryptographyDbEncryptionSdkDynamoDb(e)); + } + } diff --git a/DynamoDbEncryption/runtimes/java/build.gradle.kts b/DynamoDbEncryption/runtimes/java/build.gradle.kts index 1519c07b6..bdc5b734e 100644 --- a/DynamoDbEncryption/runtimes/java/build.gradle.kts +++ b/DynamoDbEncryption/runtimes/java/build.gradle.kts @@ -45,12 +45,12 @@ if (!caPasswordString.isNullOrBlank()) { } repositories { + mavenLocal() maven { name = "DynamoDB Local Release Repository - US West (Oregon) Region" url = URI.create("https://s3-us-west-2.amazonaws.com/dynamodb-local/release") } mavenCentral() - mavenLocal() if (caUrl != null && caPassword != null) { maven { name = "CodeArtifact" diff --git a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/DynamoDbEncryptionTransforms.java b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/DynamoDbEncryptionTransforms.java index d1c51ab4a..94cb7d63b 100644 --- a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/DynamoDbEncryptionTransforms.java +++ b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/DynamoDbEncryptionTransforms.java @@ -47,6 +47,8 @@ import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.QueryInputTransformOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.QueryOutputTransformInput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.QueryOutputTransformOutput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesInput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ScanInputTransformInput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ScanInputTransformOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ScanOutputTransformInput; @@ -259,6 +261,19 @@ public QueryOutputTransformOutput QueryOutputTransform(QueryOutputTransformInput return ToNative.QueryOutputTransformOutput(result.dtor_value()); } + /** + * Given an Item, show the intermediate values. + * + */ + public ResolveAttributesOutput ResolveAttributes(ResolveAttributesInput input) { + software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ResolveAttributesInput dafnyValue = ToDafny.ResolveAttributesInput(input); + Result result = this._impl.ResolveAttributes(dafnyValue); + if (result.is_Failure()) { + throw ToNative.Error(result.dtor_error()); + } + return ToNative.ResolveAttributesOutput(result.dtor_value()); + } + public ScanInputTransformOutput ScanInputTransform(ScanInputTransformInput input) { software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ScanInputTransformInput dafnyValue = ToDafny.ScanInputTransformInput(input); Result result = this._impl.ScanInputTransform(dafnyValue); diff --git a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToDafny.java b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToDafny.java index 995f09658..d543aeb3d 100644 --- a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToDafny.java +++ b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToDafny.java @@ -3,9 +3,15 @@ // Do not modify this file. This file is machine generated, and any changes to it will be overwritten. package software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms; +import Wrappers_Compile.Option; +import dafny.DafnyMap; import dafny.DafnySequence; import java.lang.Character; +import java.lang.Integer; import java.lang.RuntimeException; +import java.lang.String; +import java.util.Map; +import java.util.Objects; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.BatchExecuteStatementInputTransformInput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.BatchExecuteStatementInputTransformOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.BatchExecuteStatementOutputTransformInput; @@ -45,6 +51,8 @@ import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.QueryInputTransformOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.QueryOutputTransformInput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.QueryOutputTransformOutput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ResolveAttributesInput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ResolveAttributesOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ScanInputTransformInput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ScanInputTransformOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ScanOutputTransformInput; @@ -64,6 +72,7 @@ import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.CollectionOfErrors; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.DynamoDbEncryptionTransformsException; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.OpaqueError; +import software.amazon.cryptography.services.dynamodb.internaldafny.types.AttributeValue; import software.amazon.cryptography.services.dynamodb.internaldafny.types.BatchExecuteStatementInput; import software.amazon.cryptography.services.dynamodb.internaldafny.types.BatchExecuteStatementOutput; import software.amazon.cryptography.services.dynamodb.internaldafny.types.BatchGetItemInput; @@ -388,6 +397,28 @@ public static QueryOutputTransformOutput QueryOutputTransformOutput( return new QueryOutputTransformOutput(transformedOutput); } + public static ResolveAttributesInput ResolveAttributesInput( + software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesInput nativeValue) { + DafnySequence tableName; + tableName = software.amazon.smithy.dafny.conversion.ToDafny.Simple.CharacterSequence(nativeValue.TableName()); + DafnyMap, ? extends AttributeValue> item; + item = software.amazon.cryptography.services.dynamodb.internaldafny.ToDafny.AttributeMap(nativeValue.Item()); + Option version; + version = Objects.nonNull(nativeValue.Version()) ? + Option.create_Some((nativeValue.Version())) + : Option.create_None(); + return new ResolveAttributesInput(tableName, item, version); + } + + public static ResolveAttributesOutput ResolveAttributesOutput( + software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesOutput nativeValue) { + DafnyMap, ? extends DafnySequence> virtualFields; + virtualFields = ToDafny.StringMap(nativeValue.VirtualFields()); + DafnyMap, ? extends DafnySequence> compoundBeacons; + compoundBeacons = ToDafny.StringMap(nativeValue.CompoundBeacons()); + return new ResolveAttributesOutput(virtualFields, compoundBeacons); + } + public static ScanInputTransformInput ScanInputTransformInput( software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ScanInputTransformInput nativeValue) { ScanInput sdkInput; @@ -514,6 +545,14 @@ public static Error Error(DynamoDbEncryptionTransformsException nativeValue) { return new Error_DynamoDbEncryptionTransformsException(message); } + public static DafnyMap, ? extends DafnySequence> StringMap( + Map nativeValue) { + return software.amazon.smithy.dafny.conversion.ToDafny.Aggregate.GenericToMap( + nativeValue, + software.amazon.smithy.dafny.conversion.ToDafny.Simple::CharacterSequence, + software.amazon.smithy.dafny.conversion.ToDafny.Simple::CharacterSequence); + } + public static IDynamoDbEncryptionTransformsClient DynamoDbEncryptionTransforms( DynamoDbEncryptionTransforms nativeValue) { return nativeValue.impl(); diff --git a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToNative.java b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToNative.java index 1bf22e965..158939c10 100644 --- a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToNative.java +++ b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/ToNative.java @@ -3,7 +3,12 @@ // Do not modify this file. This file is machine generated, and any changes to it will be overwritten. package software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms; +import dafny.DafnyMap; +import dafny.DafnySequence; +import java.lang.Character; import java.lang.RuntimeException; +import java.lang.String; +import java.util.Map; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.Error; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.Error_CollectionOfErrors; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.Error_DynamoDbEncryptionTransformsException; @@ -48,6 +53,8 @@ import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.QueryInputTransformOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.QueryOutputTransformInput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.QueryOutputTransformOutput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesInput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ScanInputTransformInput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ScanInputTransformOutput; import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ScanOutputTransformInput; @@ -374,6 +381,25 @@ public static QueryOutputTransformOutput QueryOutputTransformOutput( return nativeBuilder.build(); } + public static ResolveAttributesInput ResolveAttributesInput( + software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ResolveAttributesInput dafnyValue) { + ResolveAttributesInput.Builder nativeBuilder = ResolveAttributesInput.builder(); + nativeBuilder.TableName(software.amazon.smithy.dafny.conversion.ToNative.Simple.String(dafnyValue.dtor_TableName())); + nativeBuilder.Item(software.amazon.cryptography.services.dynamodb.internaldafny.ToNative.AttributeMap(dafnyValue.dtor_Item())); + if (dafnyValue.dtor_Version().is_Some()) { + nativeBuilder.Version((dafnyValue.dtor_Version().dtor_value())); + } + return nativeBuilder.build(); + } + + public static ResolveAttributesOutput ResolveAttributesOutput( + software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ResolveAttributesOutput dafnyValue) { + ResolveAttributesOutput.Builder nativeBuilder = ResolveAttributesOutput.builder(); + nativeBuilder.VirtualFields(ToNative.StringMap(dafnyValue.dtor_VirtualFields())); + nativeBuilder.CompoundBeacons(ToNative.StringMap(dafnyValue.dtor_CompoundBeacons())); + return nativeBuilder.build(); + } + public static ScanInputTransformInput ScanInputTransformInput( software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.internaldafny.types.ScanInputTransformInput dafnyValue) { ScanInputTransformInput.Builder nativeBuilder = ScanInputTransformInput.builder(); @@ -490,6 +516,14 @@ public static UpdateItemOutputTransformOutput UpdateItemOutputTransformOutput( return nativeBuilder.build(); } + public static Map StringMap( + DafnyMap, ? extends DafnySequence> dafnyValue) { + return software.amazon.smithy.dafny.conversion.ToNative.Aggregate.GenericToMap( + dafnyValue, + software.amazon.smithy.dafny.conversion.ToNative.Simple::String, + software.amazon.smithy.dafny.conversion.ToNative.Simple::String); + } + public static DynamoDbEncryptionTransforms DynamoDbEncryptionTransforms( IDynamoDbEncryptionTransformsClient dafnyValue) { return new DynamoDbEncryptionTransforms(dafnyValue); diff --git a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/model/ResolveAttributesInput.java b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/model/ResolveAttributesInput.java new file mode 100644 index 000000000..da8ecbedf --- /dev/null +++ b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/model/ResolveAttributesInput.java @@ -0,0 +1,161 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// Do not modify this file. This file is machine generated, and any changes to it will be overwritten. +package software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model; + +import java.util.Map; +import java.util.Objects; +import software.amazon.awssdk.services.dynamodb.model.AttributeValue; + +public class ResolveAttributesInput { + /** + * Use the config for this Table. + */ + private final String TableName; + + /** + * The Item to be examined. + */ + private final Map Item; + + /** + * The beacon version to use. Defaults to 'writeVersion'. + */ + private final int Version; + + protected ResolveAttributesInput(BuilderImpl builder) { + this.TableName = builder.TableName(); + this.Item = builder.Item(); + this.Version = builder.Version(); + } + + /** + * @return Use the config for this Table. + */ + public String TableName() { + return this.TableName; + } + + /** + * @return The Item to be examined. + */ + public Map Item() { + return this.Item; + } + + /** + * @return The beacon version to use. Defaults to 'writeVersion'. + */ + public int Version() { + return this.Version; + } + + public Builder toBuilder() { + return new BuilderImpl(this); + } + + public static Builder builder() { + return new BuilderImpl(); + } + + public interface Builder { + /** + * @param TableName Use the config for this Table. + */ + Builder TableName(String TableName); + + /** + * @return Use the config for this Table. + */ + String TableName(); + + /** + * @param Item The Item to be examined. + */ + Builder Item(Map Item); + + /** + * @return The Item to be examined. + */ + Map Item(); + + /** + * @param Version The beacon version to use. Defaults to 'writeVersion'. + */ + Builder Version(int Version); + + /** + * @return The beacon version to use. Defaults to 'writeVersion'. + */ + int Version(); + + ResolveAttributesInput build(); + } + + static class BuilderImpl implements Builder { + protected String TableName; + + protected Map Item; + + protected int Version; + + private boolean _VersionSet = false; + + protected BuilderImpl() { + } + + protected BuilderImpl(ResolveAttributesInput model) { + this.TableName = model.TableName(); + this.Item = model.Item(); + this.Version = model.Version(); + this._VersionSet = true; + } + + public Builder TableName(String TableName) { + this.TableName = TableName; + return this; + } + + public String TableName() { + return this.TableName; + } + + public Builder Item(Map Item) { + this.Item = Item; + return this; + } + + public Map Item() { + return this.Item; + } + + public Builder Version(int Version) { + this.Version = Version; + this._VersionSet = true; + return this; + } + + public int Version() { + return this.Version; + } + + public ResolveAttributesInput build() { + if (Objects.isNull(this.TableName())) { + throw new IllegalArgumentException("Missing value for required field `TableName`"); + } + if (Objects.nonNull(this.TableName()) && this.TableName().length() < 3) { + throw new IllegalArgumentException("The size of `TableName` must be greater than or equal to 3"); + } + if (Objects.nonNull(this.TableName()) && this.TableName().length() > 255) { + throw new IllegalArgumentException("The size of `TableName` must be less than or equal to 255"); + } + if (Objects.isNull(this.Item())) { + throw new IllegalArgumentException("Missing value for required field `Item`"); + } + if (this._VersionSet && this.Version() < 1) { + throw new IllegalArgumentException("`Version` must be greater than or equal to 1"); + } + return new ResolveAttributesInput(this); + } + } +} diff --git a/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/model/ResolveAttributesOutput.java b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/model/ResolveAttributesOutput.java new file mode 100644 index 000000000..478756a90 --- /dev/null +++ b/DynamoDbEncryption/runtimes/java/src/main/smithy-generated/software/amazon/cryptography/dbencryptionsdk/dynamodb/transforms/model/ResolveAttributesOutput.java @@ -0,0 +1,112 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 +// Do not modify this file. This file is machine generated, and any changes to it will be overwritten. +package software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model; + +import java.util.Map; +import java.util.Objects; + +public class ResolveAttributesOutput { + /** + * Full plaintext of all calculable virtual fields. + */ + private final Map VirtualFields; + + /** + * Full plaintext of all calculable compound beacons. + */ + private final Map CompoundBeacons; + + protected ResolveAttributesOutput(BuilderImpl builder) { + this.VirtualFields = builder.VirtualFields(); + this.CompoundBeacons = builder.CompoundBeacons(); + } + + /** + * @return Full plaintext of all calculable virtual fields. + */ + public Map VirtualFields() { + return this.VirtualFields; + } + + /** + * @return Full plaintext of all calculable compound beacons. + */ + public Map CompoundBeacons() { + return this.CompoundBeacons; + } + + public Builder toBuilder() { + return new BuilderImpl(this); + } + + public static Builder builder() { + return new BuilderImpl(); + } + + public interface Builder { + /** + * @param VirtualFields Full plaintext of all calculable virtual fields. + */ + Builder VirtualFields(Map VirtualFields); + + /** + * @return Full plaintext of all calculable virtual fields. + */ + Map VirtualFields(); + + /** + * @param CompoundBeacons Full plaintext of all calculable compound beacons. + */ + Builder CompoundBeacons(Map CompoundBeacons); + + /** + * @return Full plaintext of all calculable compound beacons. + */ + Map CompoundBeacons(); + + ResolveAttributesOutput build(); + } + + static class BuilderImpl implements Builder { + protected Map VirtualFields; + + protected Map CompoundBeacons; + + protected BuilderImpl() { + } + + protected BuilderImpl(ResolveAttributesOutput model) { + this.VirtualFields = model.VirtualFields(); + this.CompoundBeacons = model.CompoundBeacons(); + } + + public Builder VirtualFields(Map VirtualFields) { + this.VirtualFields = VirtualFields; + return this; + } + + public Map VirtualFields() { + return this.VirtualFields; + } + + public Builder CompoundBeacons(Map CompoundBeacons) { + this.CompoundBeacons = CompoundBeacons; + return this; + } + + public Map CompoundBeacons() { + return this.CompoundBeacons; + } + + public ResolveAttributesOutput build() { + if (Objects.isNull(this.VirtualFields())) { + throw new IllegalArgumentException("Missing value for required field `VirtualFields`"); + } + if (Objects.isNull(this.CompoundBeacons())) { + throw new IllegalArgumentException("Missing value for required field `CompoundBeacons`"); + } + return new ResolveAttributesOutput(this); + } + } +} diff --git a/Examples/runtimes/java/DynamoDbEncryption/build.gradle.kts b/Examples/runtimes/java/DynamoDbEncryption/build.gradle.kts index 8c69ee14a..9d7e54e84 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/build.gradle.kts +++ b/Examples/runtimes/java/DynamoDbEncryption/build.gradle.kts @@ -38,12 +38,12 @@ if (!caPasswordString.isNullOrBlank()) { } repositories { + mavenLocal() maven { name = "DynamoDB Local Release Repository - US West (Oregon) Region" url = URI.create("https://s3-us-west-2.amazonaws.com/dynamodb-local/release") } mavenCentral() - mavenLocal() if (caUrl != null && caPassword != null) { maven { name = "CodeArtifact" diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/CompoundBeaconSearchableEncryptionExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/CompoundBeaconSearchableEncryptionExample.java index 062057e53..83897e2df 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/CompoundBeaconSearchableEncryptionExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/CompoundBeaconSearchableEncryptionExample.java @@ -27,6 +27,9 @@ import software.amazon.cryptography.dbencryptionsdk.dynamodb.model.EncryptedPart; import software.amazon.cryptography.dbencryptionsdk.dynamodb.model.SingleKeyStore; import software.amazon.cryptography.dbencryptionsdk.dynamodb.model.StandardBeacon; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.DynamoDbEncryptionTransforms; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesInput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesOutput; import software.amazon.cryptography.keystore.KeyStore; import software.amazon.cryptography.keystore.model.CreateKeyOutput; import software.amazon.cryptography.keystore.model.KMSConfiguration; @@ -220,14 +223,49 @@ public static void PutItemQueryItemWithCompoundBeacon(String ddbTableName, Strin .build(); tableConfigs.put(ddbTableName, config); - // 9. Create the DynamoDb Encryption Interceptor - DynamoDbEncryptionInterceptor encryptionInterceptor = DynamoDbEncryptionInterceptor.builder() - .config(DynamoDbTablesEncryptionConfig.builder() + // 9. Create config + final DynamoDbTablesEncryptionConfig encryptionConfig = + DynamoDbTablesEncryptionConfig.builder() .tableEncryptionConfigs(tableConfigs) - .build()) + .build(); + + // 10. Create an item with both attributes used in the compound beacon. + final HashMap item = new HashMap<>(); + item.put("work_id", AttributeValue.builder().s("9ce39272-8068-4efd-a211-cd162ad65d4c").build()); + item.put("inspection_date", AttributeValue.builder().s("2023-06-13").build()); + item.put("inspector_id_last4", AttributeValue.builder().s("5678").build()); + item.put("unit", AttributeValue.builder().s("011899988199").build()); + + // 11. If developing or debugging, verify config by checking compound beacon values directly + final DynamoDbEncryptionTransforms trans = DynamoDbEncryptionTransforms.builder() + .DynamoDbTablesEncryptionConfig(encryptionConfig).build(); + + + final ResolveAttributesInput resolveInput = ResolveAttributesInput.builder() + .TableName(ddbTableName) + .Item(item) + .Version(1) + .build(); + + final ResolveAttributesOutput resolveOutput = trans.ResolveAttributes(resolveInput); + + // VirtualFields is empty because we have no Virtual Fields configured + assert resolveOutput.VirtualFields().isEmpty(); + + // Verify that CompoundBeacons has the expected value + Map cbs = new HashMap<>(); + cbs.put("last4UnitCompound", "L-5678.U-011899988199"); + assert resolveOutput.CompoundBeacons().equals(cbs); + // Note : the compound beacon actually stored in the table is not "L-5678.U-011899988199" + // but rather something like "L-abc.U-123", as both parts are EncryptedParts + // and therefore the text is replaced by the associated beacon + + // 12. Create the DynamoDb Encryption Interceptor + DynamoDbEncryptionInterceptor encryptionInterceptor = DynamoDbEncryptionInterceptor.builder() + .config(encryptionConfig) .build(); - // 10. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above + // 13. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above final DynamoDbClient ddb = DynamoDbClient.builder() .overrideConfiguration( ClientOverrideConfiguration.builder() @@ -235,14 +273,13 @@ public static void PutItemQueryItemWithCompoundBeacon(String ddbTableName, Strin .build()) .build(); - // Perform PutItem and Query - PutAndQueryItemWithCompoundBeacon(ddb, ddbTableName); + PutAndQueryItemWithCompoundBeacon(ddb, ddbTableName, item); // If instead you were working in a multi-threaded context // it might look like this Runnable myThread = () -> { for(int i = 0; i < 20; ++i) { - PutAndQueryItemWithCompoundBeacon(ddb, ddbTableName); + PutAndQueryItemWithCompoundBeacon(ddb, ddbTableName, item); } }; ExecutorService pool = Executors.newFixedThreadPool(MAX_CONCURRENT_QUERY_THREADS); @@ -253,15 +290,8 @@ public static void PutItemQueryItemWithCompoundBeacon(String ddbTableName, Strin try {pool.awaitTermination(30, TimeUnit.SECONDS);} catch (Exception e) {} } - public static void PutAndQueryItemWithCompoundBeacon(DynamoDbClient ddb, String ddbTableName) { - - // 11. Put an item with both attributes used in the compound beacon. - final HashMap item = new HashMap<>(); - item.put("work_id", AttributeValue.builder().s("9ce39272-8068-4efd-a211-cd162ad65d4c").build()); - item.put("inspection_date", AttributeValue.builder().s("2023-06-13").build()); - item.put("inspector_id_last4", AttributeValue.builder().s("5678").build()); - item.put("unit", AttributeValue.builder().s("011899988199").build()); - + public static void PutAndQueryItemWithCompoundBeacon(DynamoDbClient ddb, String ddbTableName, HashMap item) { + // 14. Write the item to the table final PutItemRequest putRequest = PutItemRequest.builder() .tableName(ddbTableName) .item(item) @@ -271,7 +301,7 @@ public static void PutAndQueryItemWithCompoundBeacon(DynamoDbClient ddb, String // Validate object put successfully assert 200 == putResponse.sdkHttpResponse().statusCode(); - // 12. Query for the item we just put. + // 15. Query for the item we just put. Map expressionAttributesNames = new HashMap<>(); expressionAttributesNames.put("#compound", "last4UnitCompound"); diff --git a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/VirtualBeaconSearchableEncryptionExample.java b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/VirtualBeaconSearchableEncryptionExample.java index 49f1f7d79..138fb7306 100644 --- a/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/VirtualBeaconSearchableEncryptionExample.java +++ b/Examples/runtimes/java/DynamoDbEncryption/src/main/java/software/amazon/cryptography/examples/searchableencryption/VirtualBeaconSearchableEncryptionExample.java @@ -24,6 +24,9 @@ import software.amazon.cryptography.dbencryptionsdk.dynamodb.model.VirtualField; import software.amazon.cryptography.dbencryptionsdk.dynamodb.model.VirtualPart; import software.amazon.cryptography.dbencryptionsdk.dynamodb.model.VirtualTransform; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.DynamoDbEncryptionTransforms; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesInput; +import software.amazon.cryptography.dbencryptionsdk.dynamodb.transforms.model.ResolveAttributesOutput; import software.amazon.cryptography.keystore.KeyStore; import software.amazon.cryptography.keystore.model.KMSConfiguration; import software.amazon.cryptography.keystore.model.KeyStoreConfig; @@ -313,14 +316,54 @@ public static void PutItemQueryItemWithVirtualBeacon(String ddbTableName, String .build(); tableConfigs.put(ddbTableName, config); - // 10. Create the DynamoDb Encryption Interceptor - DynamoDbEncryptionInterceptor encryptionInterceptor = DynamoDbEncryptionInterceptor.builder() - .config(DynamoDbTablesEncryptionConfig.builder() + // 10. Create config + final DynamoDbTablesEncryptionConfig encryptionConfig = + DynamoDbTablesEncryptionConfig.builder() .tableEncryptionConfigs(tableConfigs) - .build()) + .build(); + + // 11. Create test items + + // Create item with hasTestResult=true + final HashMap itemWithHasTestResult = new HashMap<>(); + itemWithHasTestResult.put("customer_id", AttributeValue.builder().s("ABC-123").build()); + itemWithHasTestResult.put("create_time", AttributeValue.builder().n("1681495205").build()); + itemWithHasTestResult.put("state", AttributeValue.builder().s("CA").build()); + itemWithHasTestResult.put("hasTestResult", AttributeValue.builder().bool(true).build()); + + // Create item with hasTestResult=false + final HashMap itemWithNoHasTestResult = new HashMap<>(); + itemWithNoHasTestResult.put("customer_id", AttributeValue.builder().s("DEF-456").build()); + itemWithNoHasTestResult.put("create_time", AttributeValue.builder().n("1681495205").build()); + itemWithNoHasTestResult.put("state", AttributeValue.builder().s("CA").build()); + itemWithNoHasTestResult.put("hasTestResult", AttributeValue.builder().bool(false).build()); + + + // 12. If developing or debugging, verify config by checking virtual field values directly + final DynamoDbEncryptionTransforms trans = DynamoDbEncryptionTransforms.builder() + .DynamoDbTablesEncryptionConfig(encryptionConfig).build(); + + final ResolveAttributesInput resolveInput = ResolveAttributesInput.builder() + .TableName(ddbTableName) + .Item(itemWithHasTestResult) + .Version(1) .build(); + final ResolveAttributesOutput resolveOutput = trans.ResolveAttributes(resolveInput); - // 11. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above + // CompoundBeacons is empty because we have no Compound Beacons configured + assert resolveOutput.CompoundBeacons().isEmpty(); + + // Verify that VirtualFields has the expected value + Map vf = new HashMap<>(); + vf.put("stateAndHasTestResult", "CAt"); + assert resolveOutput.VirtualFields().equals(vf); + + // 13. Create the DynamoDb Encryption Interceptor + DynamoDbEncryptionInterceptor encryptionInterceptor = DynamoDbEncryptionInterceptor.builder() + .config(encryptionConfig) + .build(); + + // 14. Create a new AWS SDK DynamoDb client using the DynamoDb Encryption Interceptor above final DynamoDbClient ddb = DynamoDbClient.builder() .overrideConfiguration( ClientOverrideConfiguration.builder() @@ -328,7 +371,7 @@ public static void PutItemQueryItemWithVirtualBeacon(String ddbTableName, String .build()) .build(); - // 12. Put two items into our table using the above client. + // 15. Put two items into our table using the above client. // The two items will differ only in their `customer_id` attribute (primary key) // and their `hasTestResult` attribute. // We will query against these items to demonstrate how to use our setup above @@ -341,13 +384,6 @@ public static void PutItemQueryItemWithVirtualBeacon(String ddbTableName, String // Its value will be an HMAC truncated to as many bits as the // beacon's `length` parameter; i.e. 5. - // Add record with hasTestResult=true - final HashMap itemWithHasTestResult = new HashMap<>(); - itemWithHasTestResult.put("customer_id", AttributeValue.builder().s("ABC-123").build()); - itemWithHasTestResult.put("create_time", AttributeValue.builder().n("1681495205").build()); - itemWithHasTestResult.put("state", AttributeValue.builder().s("CA").build()); - itemWithHasTestResult.put("hasTestResult", AttributeValue.builder().bool(true).build()); - final PutItemRequest itemWithHasTestResultPutRequest = PutItemRequest.builder() .tableName(ddbTableName) .item(itemWithHasTestResult) @@ -357,13 +393,6 @@ public static void PutItemQueryItemWithVirtualBeacon(String ddbTableName, String // Assert PutItem was successful assert 200 == itemWithHasTestResultPutResponse.sdkHttpResponse().statusCode(); - // Add record with hasTestResult=false - final HashMap itemWithNoHasTestResult = new HashMap<>(); - itemWithNoHasTestResult.put("customer_id", AttributeValue.builder().s("DEF-456").build()); - itemWithNoHasTestResult.put("create_time", AttributeValue.builder().n("1681495205").build()); - itemWithNoHasTestResult.put("state", AttributeValue.builder().s("CA").build()); - itemWithNoHasTestResult.put("hasTestResult", AttributeValue.builder().bool(false).build()); - final PutItemRequest itemWithNoHasTestResultPutRequest = PutItemRequest.builder() .tableName(ddbTableName) .item(itemWithNoHasTestResult) @@ -373,7 +402,7 @@ public static void PutItemQueryItemWithVirtualBeacon(String ddbTableName, String // Assert PutItem was successful assert 200 == itemWithNoHasTestResultPutResponse.sdkHttpResponse().statusCode(); - // 13. Query by stateAndHasTestResult attribute. + // 16. Query by stateAndHasTestResult attribute. // Note that we are constructing the query as if we were querying on plaintext values. // However, the DDB encryption client will detect that this attribute name has a beacon configured. // The client will add the beaconized attribute name and attribute value to the query, diff --git a/Examples/runtimes/java/Migration/DDBECToAWSDBE/build.gradle.kts b/Examples/runtimes/java/Migration/DDBECToAWSDBE/build.gradle.kts index 8c374d8eb..2af95a34c 100644 --- a/Examples/runtimes/java/Migration/DDBECToAWSDBE/build.gradle.kts +++ b/Examples/runtimes/java/Migration/DDBECToAWSDBE/build.gradle.kts @@ -37,12 +37,12 @@ if (!caPasswordString.isNullOrBlank()) { } repositories { + mavenLocal() maven { name = "DynamoDB Local Release Repository - US West (Oregon) Region" url = URI.create("https://s3-us-west-2.amazonaws.com/dynamodb-local/release") } mavenCentral() - mavenLocal() if (caUrl != null && caPassword != null) { maven { name = "CodeArtifact" diff --git a/Examples/runtimes/java/Migration/PlaintextToAWSDBE/build.gradle.kts b/Examples/runtimes/java/Migration/PlaintextToAWSDBE/build.gradle.kts index 6d040d4ad..a688e75d9 100644 --- a/Examples/runtimes/java/Migration/PlaintextToAWSDBE/build.gradle.kts +++ b/Examples/runtimes/java/Migration/PlaintextToAWSDBE/build.gradle.kts @@ -37,12 +37,12 @@ if (!caPasswordString.isNullOrBlank()) { } repositories { + mavenLocal() maven { name = "DynamoDB Local Release Repository - US West (Oregon) Region" url = URI.create("https://s3-us-west-2.amazonaws.com/dynamodb-local/release") } mavenCentral() - mavenLocal() if (caUrl != null && caPassword != null) { maven { name = "CodeArtifact" diff --git a/TestVectors/runtimes/java/build.gradle.kts b/TestVectors/runtimes/java/build.gradle.kts index a0222386a..4778aa0f6 100644 --- a/TestVectors/runtimes/java/build.gradle.kts +++ b/TestVectors/runtimes/java/build.gradle.kts @@ -47,12 +47,12 @@ if (!caPasswordString.isNullOrBlank()) { } repositories { + mavenLocal() maven { name = "DynamoDB Local Release Repository - US West (Oregon) Region" url = URI.create("https://s3-us-west-2.amazonaws.com/dynamodb-local/release") } mavenCentral() - mavenLocal() if (caUrl != null && caPassword != null) { maven { name = "CodeArtifact"