|
35 | 35 | import com.apple.foundationdb.record.lucene.directory.FDBDirectoryLockFactory;
|
36 | 36 | import com.apple.foundationdb.record.lucene.directory.FDBDirectoryWrapper;
|
37 | 37 | import com.apple.foundationdb.record.metadata.Index;
|
| 38 | +import com.apple.foundationdb.record.provider.common.FixedZeroKeyManager; |
38 | 39 | import com.apple.foundationdb.record.provider.common.RollingTestKeyManager;
|
| 40 | +import com.apple.foundationdb.record.provider.common.SerializationKeyManager; |
39 | 41 | import com.apple.foundationdb.record.provider.common.StoreTimer;
|
40 | 42 | import com.apple.foundationdb.record.provider.foundationdb.FDBExceptions;
|
41 | 43 | import com.apple.foundationdb.record.provider.foundationdb.FDBRecordContext;
|
|
70 | 72 |
|
71 | 73 | import javax.annotation.Nonnull;
|
72 | 74 | import javax.annotation.Nullable;
|
| 75 | +import javax.crypto.KeyGenerator; |
| 76 | +import javax.crypto.SecretKey; |
73 | 77 | import java.io.IOException;
|
74 | 78 | import java.security.GeneralSecurityException;
|
75 | 79 | import java.time.Duration;
|
|
104 | 108 | import static com.apple.foundationdb.record.metadata.Key.Expressions.field;
|
105 | 109 | import static com.apple.foundationdb.record.metadata.Key.Expressions.function;
|
106 | 110 | import static org.hamcrest.MatcherAssert.assertThat;
|
| 111 | +import static org.hamcrest.Matchers.containsString; |
| 112 | +import static org.hamcrest.Matchers.instanceOf; |
107 | 113 | import static org.junit.jupiter.api.Assertions.assertEquals;
|
108 | 114 | import static org.junit.jupiter.api.Assertions.assertFalse;
|
109 | 115 | import static org.junit.jupiter.api.Assertions.assertNotNull;
|
@@ -893,6 +899,52 @@ void sampledDelete(boolean isSynthetic, boolean isGrouped, long seed) throws IOE
|
893 | 899 | assertThat(partitionCounts, Matchers.contains(5, 3, 4)));
|
894 | 900 | }
|
895 | 901 |
|
| 902 | + static Stream<Arguments> changingEncryptionKey() { |
| 903 | + return Stream.concat(Stream.of(Arguments.of(true, true, 288513), |
| 904 | + Arguments.of(false, false, 792025)), |
| 905 | + RandomizedTestUtils.randomArguments(random -> |
| 906 | + Arguments.of(random.nextBoolean(), random.nextBoolean(), random.nextLong()))); |
| 907 | + } |
| 908 | + |
| 909 | + @ParameterizedTest |
| 910 | + @MethodSource |
| 911 | + void changingEncryptionKey(boolean isSynthetic, boolean isGrouped, long seed) throws IOException, GeneralSecurityException { |
| 912 | + final LuceneIndexTestDataModel dataModel = new LuceneIndexTestDataModel.Builder(seed, this::getStoreBuilder, pathManager) |
| 913 | + .setIsGrouped(isGrouped) |
| 914 | + .setIsSynthetic(isSynthetic) |
| 915 | + .setPrimaryKeySegmentIndexEnabled(true) |
| 916 | + .build(); |
| 917 | + |
| 918 | + final RecordLayerPropertyStorage.Builder contextPropsBuilder = RecordLayerPropertyStorage.newBuilder() |
| 919 | + .addProp(LuceneRecordContextProperties.LUCENE_INDEX_COMPRESSION_ENABLED, true) |
| 920 | + .addProp(LuceneRecordContextProperties.LUCENE_INDEX_ENCRYPTION_ENABLED, true); |
| 921 | + final KeyGenerator keyGen = KeyGenerator.getInstance("AES"); |
| 922 | + keyGen.init(128); |
| 923 | + final SecretKey key1 = keyGen.generateKey(); |
| 924 | + final SerializationKeyManager keyManager1 = new FixedZeroKeyManager(key1, null, null); |
| 925 | + contextPropsBuilder.addProp(LuceneRecordContextProperties.LUCENE_INDEX_KEY_MANAGER, keyManager1); |
| 926 | + final RecordLayerPropertyStorage contextProps1 = contextPropsBuilder.build(); |
| 927 | + |
| 928 | + try (FDBRecordContext context = openContext(contextProps1)) { |
| 929 | + dataModel.saveRecordsToAllGroups(20, context); |
| 930 | + commit(context); |
| 931 | + } |
| 932 | + |
| 933 | + explicitMergeIndex(dataModel.index, contextProps1, dataModel.schemaSetup); |
| 934 | + |
| 935 | + final SecretKey key2 = keyGen.generateKey(); |
| 936 | + final SerializationKeyManager keyManager2 = new FixedZeroKeyManager(key2, null, null); |
| 937 | + contextPropsBuilder.removeProp(LuceneRecordContextProperties.LUCENE_INDEX_KEY_MANAGER); |
| 938 | + contextPropsBuilder.addProp(LuceneRecordContextProperties.LUCENE_INDEX_KEY_MANAGER, keyManager2); |
| 939 | + final RecordLayerPropertyStorage contextProps2 = contextPropsBuilder.build(); |
| 940 | + IOException ioException = assertThrows(IOException.class, |
| 941 | + () -> dataModel.validate(() -> openContext(contextProps2))); |
| 942 | + assertThat(ioException.getCause(), instanceOf(RecordCoreException.class)); |
| 943 | + assertThat(ioException.getCause().getMessage(), containsString("Lucene data decoding failure")); |
| 944 | + assertThat(ioException.getCause().getCause(), instanceOf(GeneralSecurityException.class)); |
| 945 | + |
| 946 | + } |
| 947 | + |
896 | 948 | private static Stream<Arguments> concurrentParameters() {
|
897 | 949 | // only run the individual tests with synthetic during nightly, the mix runs both
|
898 | 950 | return Stream.concat(Stream.of(false),
|
|
0 commit comments