Skip to content

Commit 136b025

Browse files
authored
Merge pull request #13 from justplaz/add-tests
Add more integ tests, add some unit tests, add Jacoco for test coverage reporting
2 parents ae6212e + 140a136 commit 136b025

File tree

9 files changed

+296
-8
lines changed

9 files changed

+296
-8
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ Integration tests are included. To test them, certain environment variables need
77

88
* `AWS_S3EC_TEST_BUCKET` - The bucket to write test values to
99
* `AWS_S3EC_TEST_KMS_KEY_ID` - The key id for the KMS key used for KMS tests
10-
* `AWS_S3EC_TEST_KMS_REGION` - The region the KMS key resides e.g. us-east-1`
10+
* `AWS_S3EC_TEST_KMS_KEY_ALIAS` - An alias for the KMS key used for KMS tests. The alias must reference the key ID above.
11+
* `AWS_REGION` - The region the AWS resources (KMS key, S3 bucket) resides e.g. "us-east-1"
1112

1213
## Migration
1314

pom.xml

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,35 @@
108108
<artifactId>maven-surefire-plugin</artifactId>
109109
<version>2.22.2</version>
110110
</plugin>
111+
112+
<plugin>
113+
<groupId>org.jacoco</groupId>
114+
<artifactId>jacoco-maven-plugin</artifactId>
115+
<version>0.8.8</version>
116+
<executions>
117+
<execution>
118+
<goals>
119+
<goal>prepare-agent</goal>
120+
</goals>
121+
</execution>
122+
<execution>
123+
<id>report</id>
124+
<phase>prepare-package</phase>
125+
<goals>
126+
<goal>report</goal>
127+
</goals>
128+
</execution>
129+
<execution>
130+
<id>check</id>
131+
<goals>
132+
<goal>check</goal>
133+
</goals>
134+
</execution>
135+
</executions>
136+
</plugin>
111137
</plugins>
112138
</build>
113139

114-
</project>
140+
141+
142+
</project>

src/main/java/software/amazon/encryption/s3/materials/AesKeyring.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import javax.crypto.Cipher;
1010
import javax.crypto.SecretKey;
1111
import javax.crypto.spec.GCMParameterSpec;
12+
1213
import software.amazon.encryption.s3.S3EncryptionClientException;
1314
import software.amazon.encryption.s3.algorithms.AlgorithmSuite;
1415

@@ -169,7 +170,10 @@ protected Builder builder() {
169170
return this;
170171
}
171172

172-
public Builder wrappingKey(SecretKey wrappingKey) {
173+
public Builder wrappingKey(final SecretKey wrappingKey) {
174+
if (wrappingKey == null) {
175+
throw new S3EncryptionClientException("Wrapping key cannot be null!");
176+
}
173177
if (!wrappingKey.getAlgorithm().equals(KEY_ALGORITHM)) {
174178
throw new S3EncryptionClientException("Invalid algorithm: " + wrappingKey.getAlgorithm() + ", expecting " + KEY_ALGORITHM);
175179
}

src/main/java/software/amazon/encryption/s3/materials/S3Keyring.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,18 @@ public BuilderT enableLegacyModes(boolean shouldEnableLegacyModes) {
113113
return builder();
114114
}
115115

116-
public BuilderT secureRandom(SecureRandom secureRandom) {
116+
public BuilderT secureRandom(final SecureRandom secureRandom) {
117+
if (secureRandom == null) {
118+
throw new S3EncryptionClientException("SecureRandom cannot be null!");
119+
}
117120
_secureRandom = secureRandom;
118121
return builder();
119122
}
120123

121-
public BuilderT dataKeyGenerator(DataKeyGenerator dataKeyGenerator) {
124+
public BuilderT dataKeyGenerator(final DataKeyGenerator dataKeyGenerator) {
125+
if (dataKeyGenerator == null) {
126+
throw new S3EncryptionClientException("DataKeyGenerator cannot be null!");
127+
}
122128
_dataKeyGenerator = dataKeyGenerator;
123129
return builder();
124130
}

src/test/java/S3EncryptionClientTest.java renamed to src/test/java/software/amazon/encryption/s3/S3EncryptionClientCompatibilityTest.java

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
package software.amazon.encryption.s3;
2+
13
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertThrows;
25
import static software.amazon.encryption.s3.S3EncryptionClient.withAdditionalEncryptionContext;
36

47
import com.amazonaws.regions.Region;
@@ -35,13 +38,16 @@
3538
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
3639
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
3740
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
38-
import software.amazon.encryption.s3.S3EncryptionClient;
3941

40-
public class S3EncryptionClientTest {
42+
/**
43+
* This class is an integration test for verifying compatibility of ciphertexts
44+
* between V1, V2, and V3 clients under various conditions.
45+
*/
46+
public class S3EncryptionClientCompatibilityTest {
4147

4248
private static final String BUCKET = System.getenv("AWS_S3EC_TEST_BUCKET");
4349
private static final String KMS_KEY_ID = System.getenv("AWS_S3EC_TEST_KMS_KEY_ID");
44-
private static final Region KMS_REGION = Region.getRegion(Regions.fromName(System.getenv("AWS_S3EC_TEST_KMS_REGION")));
50+
private static final Region KMS_REGION = Region.getRegion(Regions.fromName(System.getenv("AWS_REGION")));
4551

4652
private static SecretKey AES_KEY;
4753
private static KeyPair RSA_KEY_PAIR;
@@ -565,4 +571,57 @@ public void KmsContextV3toV3() {
565571
String output = objectResponse.asUtf8String();
566572
assertEquals(input, output);
567573
}
574+
575+
@Test
576+
public void AesCbcV1toV3FailsWhenLegacyModeDisabled() {
577+
final String BUCKET_KEY = "aes-cbc-v1-to-v3";
578+
579+
EncryptionMaterialsProvider materialsProvider =
580+
new StaticEncryptionMaterialsProvider(new EncryptionMaterials(AES_KEY));
581+
CryptoConfiguration v1CryptoConfig =
582+
new CryptoConfiguration(CryptoMode.EncryptionOnly);
583+
AmazonS3Encryption v1Client = AmazonS3EncryptionClient.encryptionBuilder()
584+
.withCryptoConfiguration(v1CryptoConfig)
585+
.withEncryptionMaterials(materialsProvider)
586+
.build();
587+
588+
S3Client v3Client = S3EncryptionClient.builder()
589+
.aesKey(AES_KEY)
590+
.enableLegacyModes(false)
591+
.build();
592+
593+
final String input = "AesCbcV1toV3";
594+
v1Client.putObject(BUCKET, BUCKET_KEY, input);
595+
596+
assertThrows(S3EncryptionClientException.class, () -> v3Client.getObjectAsBytes(builder -> builder
597+
.bucket(BUCKET)
598+
.key(BUCKET_KEY)));
599+
}
600+
601+
@Test
602+
public void AesWrapV1toV3FailsWhenLegacyModeDisabled() {
603+
final String BUCKET_KEY = "aes-wrap-v1-to-v3";
604+
605+
EncryptionMaterialsProvider materialsProvider =
606+
new StaticEncryptionMaterialsProvider(new EncryptionMaterials(AES_KEY));
607+
CryptoConfiguration v1CryptoConfig =
608+
new CryptoConfiguration(CryptoMode.AuthenticatedEncryption);
609+
AmazonS3Encryption v1Client = AmazonS3EncryptionClient.encryptionBuilder()
610+
.withCryptoConfiguration(v1CryptoConfig)
611+
.withEncryptionMaterials(materialsProvider)
612+
.build();
613+
614+
S3Client v3Client = S3EncryptionClient.builder()
615+
.aesKey(AES_KEY)
616+
.enableLegacyModes(false)
617+
.build();
618+
619+
final String input = "AesGcmV1toV3";
620+
v1Client.putObject(BUCKET, BUCKET_KEY, input);
621+
622+
assertThrows(S3EncryptionClientException.class, () -> v3Client.getObjectAsBytes(builder -> builder
623+
.bucket(BUCKET)
624+
.key(BUCKET_KEY)));
625+
}
626+
568627
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package software.amazon.encryption.s3;
2+
3+
import org.junit.jupiter.api.Test;
4+
import software.amazon.awssdk.core.ResponseBytes;
5+
import software.amazon.awssdk.core.sync.RequestBody;
6+
import software.amazon.awssdk.services.s3.S3Client;
7+
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
8+
9+
import javax.crypto.KeyGenerator;
10+
import javax.crypto.SecretKey;
11+
import java.security.KeyPair;
12+
import java.security.KeyPairGenerator;
13+
import java.security.NoSuchAlgorithmException;
14+
import java.util.HashMap;
15+
import java.util.Map;
16+
17+
import static org.junit.jupiter.api.Assertions.assertEquals;
18+
import static org.junit.jupiter.api.Assertions.assertThrows;
19+
import static software.amazon.encryption.s3.S3EncryptionClient.withAdditionalEncryptionContext;
20+
21+
/**
22+
* This class is an integration test for verifying behavior of the V3 client
23+
* under various scenarios.
24+
*/
25+
public class S3EncryptionClientTest {
26+
27+
private static final String BUCKET = System.getenv("AWS_S3EC_TEST_BUCKET");
28+
private static final String KMS_KEY_ID = System.getenv("AWS_S3EC_TEST_KMS_KEY_ID");
29+
// This alias must point to the same key as KMS_KEY_ID
30+
private static final String KMS_KEY_ALIAS = System.getenv("AWS_S3EC_TEST_KMS_KEY_ALIAS");
31+
32+
@Test
33+
public void KmsWithAliasARN() {
34+
S3Client v3Client = S3EncryptionClient.builder()
35+
.kmsKeyId(KMS_KEY_ALIAS)
36+
.build();
37+
38+
simpleV3RoundTrip(v3Client);
39+
}
40+
41+
@Test
42+
public void KmsWithShortKeyId() {
43+
// Just assume the ARN is well-formed
44+
// Also assume that the region is set correctly
45+
final String shortId = KMS_KEY_ID.split("/")[1];
46+
47+
S3Client v3Client = S3EncryptionClient.builder()
48+
.kmsKeyId(shortId)
49+
.build();
50+
51+
simpleV3RoundTrip(v3Client);
52+
}
53+
54+
@Test
55+
public void KmsAliasARNToKeyId() {
56+
S3Client aliasClient = S3EncryptionClient.builder()
57+
.kmsKeyId(KMS_KEY_ALIAS)
58+
.build();
59+
60+
S3Client keyIdClient = S3EncryptionClient.builder()
61+
.kmsKeyId(KMS_KEY_ID)
62+
.build();
63+
64+
final String input = "KmsAliasARNToKeyId";
65+
Map<String, String> encryptionContext = new HashMap<>();
66+
encryptionContext.put("user-metadata-key", "user-metadata-value-alias-to-id");
67+
68+
aliasClient.putObject(builder -> builder
69+
.bucket(BUCKET)
70+
.key(input)
71+
.overrideConfiguration(withAdditionalEncryptionContext(encryptionContext)),
72+
RequestBody.fromString(input));
73+
74+
ResponseBytes<GetObjectResponse> objectResponse = keyIdClient.getObjectAsBytes(builder -> builder
75+
.bucket(BUCKET)
76+
.key(input)
77+
.overrideConfiguration(withAdditionalEncryptionContext(encryptionContext)));
78+
String output = objectResponse.asUtf8String();
79+
assertEquals(input, output);
80+
}
81+
82+
@Test
83+
public void AesKeyringWithInvalidAesKey() throws NoSuchAlgorithmException {
84+
SecretKey invalidAesKey;
85+
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
86+
keyGen.init(56);
87+
invalidAesKey = keyGen.generateKey();
88+
89+
assertThrows(S3EncryptionClientException.class, () -> S3EncryptionClient.builder()
90+
.aesKey(invalidAesKey)
91+
.build());
92+
}
93+
94+
@Test
95+
public void RsaKeyringWithInvalidRsaKey() throws NoSuchAlgorithmException {
96+
KeyPair invalidRsaKey;
97+
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("EC");
98+
keyPairGen.initialize(256);
99+
invalidRsaKey = keyPairGen.generateKeyPair();
100+
101+
assertThrows(S3EncryptionClientException.class, () -> S3EncryptionClient.builder()
102+
.rsaKeyPair(invalidRsaKey)
103+
.build());
104+
}
105+
106+
/**
107+
* A simple, reusable round-trip (encryption + decryption) using a given
108+
* S3Client. Useful for testing client configuration.
109+
* @param v3Client the client under test
110+
*/
111+
private void simpleV3RoundTrip(final S3Client v3Client) {
112+
final String input = "SimpleTestOfV3EncryptionClient";
113+
114+
v3Client.putObject(builder -> builder
115+
.bucket(BUCKET)
116+
.key(input)
117+
.build(),
118+
RequestBody.fromString(input));
119+
120+
ResponseBytes<GetObjectResponse> objectResponse = v3Client.getObjectAsBytes(builder -> builder
121+
.bucket(BUCKET)
122+
.key(input)
123+
.build());
124+
String output = objectResponse.asUtf8String();
125+
assertEquals(input, output);
126+
}
127+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package software.amazon.encryption.s3.materials;
2+
3+
import org.junit.jupiter.api.Test;
4+
import software.amazon.encryption.s3.S3EncryptionClientException;
5+
6+
import static org.junit.jupiter.api.Assertions.assertThrows;
7+
8+
public class AesKeyringTest {
9+
10+
@Test
11+
public void testAesKeyringWithNullWrappingKeyFails() {
12+
assertThrows(S3EncryptionClientException.class, () -> AesKeyring.builder().wrappingKey(null));
13+
}
14+
15+
@Test
16+
public void buildAesKeyringWithNullSecureRandomFails() {
17+
assertThrows(S3EncryptionClientException.class, () -> AesKeyring.builder().secureRandom(null));
18+
}
19+
20+
@Test
21+
public void buildAesKeyringWithNullDataKeyGeneratorFails() {
22+
assertThrows(S3EncryptionClientException.class, () -> AesKeyring.builder().dataKeyGenerator(null));
23+
}
24+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package software.amazon.encryption.s3.materials;
2+
3+
import org.junit.jupiter.api.Test;
4+
import software.amazon.encryption.s3.S3EncryptionClientException;
5+
6+
import static org.junit.jupiter.api.Assertions.assertThrows;
7+
8+
public class KmsKeyringTest {
9+
10+
@Test
11+
public void buildAesKeyringWithNullSecureRandomFails() {
12+
assertThrows(S3EncryptionClientException.class, () -> AesKeyring.builder().secureRandom(null));
13+
}
14+
15+
@Test
16+
public void buildAesKeyringWithNullDataKeyGeneratorFails() {
17+
assertThrows(S3EncryptionClientException.class, () -> AesKeyring.builder().dataKeyGenerator(null));
18+
}
19+
20+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package software.amazon.encryption.s3.materials;
2+
3+
import org.junit.jupiter.api.Test;
4+
import software.amazon.encryption.s3.S3EncryptionClientException;
5+
6+
import static org.junit.jupiter.api.Assertions.assertThrows;
7+
8+
public class RsaKeyringTest {
9+
10+
@Test
11+
public void buildAesKeyringWithNullSecureRandomFails() {
12+
assertThrows(S3EncryptionClientException.class, () -> AesKeyring.builder().secureRandom(null));
13+
}
14+
15+
@Test
16+
public void buildAesKeyringWithNullDataKeyGeneratorFails() {
17+
assertThrows(S3EncryptionClientException.class, () -> AesKeyring.builder().dataKeyGenerator(null));
18+
}
19+
}

0 commit comments

Comments
 (0)