Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,6 @@ java/.mvn/.develocity/
# rat
filtered_rat.txt
rat.txt

python/sample.parquet
Dockerfile
6 changes: 4 additions & 2 deletions cpp/src/arrow/util/io_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2248,7 +2248,8 @@ Result<void*> LoadDynamicLibrary(const char* path) {
return LoadDynamicLibrary(platform_path);
#else
constexpr int kFlags =
// All undefined symbols in the shared object are resolved before dlopen() returns.
// All undefined symbols in the shared object are resolved before dlopen()
// returns.
RTLD_NOW
// Symbols defined in this shared object are not made available to
// resolve references in subsequently loaded shared objects.
Expand Down Expand Up @@ -2310,7 +2311,8 @@ Status CloseDynamicLibrary(void* handle) {
if (dlclose(handle) == 0) {
return Status::OK();
}
// dlclose(3) man page: "On success, dlclose() returns 0; on error, it returns a nonzero value."
// dlclose(3) man page: "On success, dlclose() returns 0; on error, it returns a
// nonzero value."
auto* error = dlerror();
return Status::IOError("dlclose() failed: ", error ? error : "unknown error");
#endif
Expand Down
3 changes: 2 additions & 1 deletion cpp/src/arrow/util/io_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,8 @@ ARROW_EXPORT Result<void*> GetSymbol(void* handle, const char* name);
///
/// This wraps dlclose() except on Windows, where FreeLibrary() is called.
///
/// \return Status::OK() if the library was closed successfully, otherwise an error is returned.
/// \return Status::OK() if the library was closed successfully, otherwise an error
/// is returned.
ARROW_EXPORT Status CloseDynamicLibrary(void* handle);

template <typename T>
Expand Down
115 changes: 56 additions & 59 deletions cpp/src/parquet/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -239,64 +239,58 @@ endif()

if(PARQUET_REQUIRE_ENCRYPTION)
list(APPEND PARQUET_SHARED_PRIVATE_LINK_LIBS ${ARROW_OPENSSL_LIBS})
set(PARQUET_SRCS ${PARQUET_SRCS} encryption/aes_encryption.cc
encryption/openssl_internal.cc
encryption/encryption_utils.cc
encryption/external_dbpa_encryption.cc
encryption/external/dbpa_library_wrapper.cc
encryption/encoding_properties.cc
encryption/external/dbpa_enum_utils.cc
encryption/external/dbpa_executor.cc
encryption/external/loadable_encryptor_utils.cc
)
set(PARQUET_SRCS
${PARQUET_SRCS}
encryption/aes_encryption.cc
encryption/openssl_internal.cc
encryption/encryption_utils.cc
encryption/external_dbpa_encryption.cc
encryption/external/dbpa_library_wrapper.cc
encryption/encoding_properties.cc
encryption/external/dbpa_enum_utils.cc
encryption/external/dbpa_executor.cc
encryption/external/loadable_encryptor_utils.cc)

# Header-only dependencies for external DBPA code
include(FetchContent)

# magic_enum
FetchContent_Declare(
magic_enum_upstream
GIT_REPOSITORY https://github.com/Neargye/magic_enum.git
GIT_TAG v0.9.7
)
FetchContent_MakeAvailable(magic_enum_upstream)
fetchcontent_declare(magic_enum_upstream
GIT_REPOSITORY https://github.com/Neargye/magic_enum.git
GIT_TAG v0.9.7)
fetchcontent_makeavailable(magic_enum_upstream)
add_library(magic_enum_header_only INTERFACE)
target_include_directories(magic_enum_header_only INTERFACE ${magic_enum_upstream_SOURCE_DIR}/include)
target_include_directories(magic_enum_header_only
INTERFACE ${magic_enum_upstream_SOURCE_DIR}/include)

# tcb/span
FetchContent_Declare(
tcb_span_upstream
GIT_REPOSITORY https://github.com/tcbrindle/span.git
GIT_TAG master
)
fetchcontent_declare(tcb_span_upstream
GIT_REPOSITORY https://github.com/tcbrindle/span.git
GIT_TAG master)

# Populate sources only; do not add subproject/tests
FetchContent_GetProperties(tcb_span_upstream)
fetchcontent_getproperties(tcb_span_upstream)
if(NOT tcb_span_upstream_POPULATED)
FetchContent_Populate(tcb_span_upstream)
fetchcontent_populate(tcb_span_upstream)
endif()
add_library(tcb_span INTERFACE)
target_include_directories(tcb_span INTERFACE ${tcb_span_upstream_SOURCE_DIR}/include)

# DBPS interface (header-only)
FetchContent_Declare(
dbps_agent
GIT_REPOSITORY https://github.com/protegrity/DataBatchProtectionService.git

#TODO: Change to a specific tag/commit when we have one.
#https://github.com/protegrity/arrow/issues/179
GIT_TAG 4c808b2233ed0bc04529c3b0dbf7c214c4901043
GIT_SHALLOW FALSE
)

FetchContent_GetProperties(dbps_agent)
fetchcontent_declare(dbps_agent
GIT_REPOSITORY https://github.com/protegrity/DataBatchProtectionService.git
#TODO: Change to a specific tag/commit when we have one.
#https://github.com/protegrity/arrow/issues/179
GIT_TAG 4c808b2233ed0bc04529c3b0dbf7c214c4901043
GIT_SHALLOW FALSE)

fetchcontent_getproperties(dbps_agent)
if(NOT dbps_agent_POPULATED)
FetchContent_Populate(dbps_agent)
fetchcontent_populate(dbps_agent)
endif()
add_library(dbps_interface INTERFACE)
# Expose dbpa_interface.h and friends from DBPS
target_include_directories(dbps_interface INTERFACE
${dbps_agent_SOURCE_DIR}/src/common)
target_include_directories(dbps_interface INTERFACE ${dbps_agent_SOURCE_DIR}/src/common)

# Allows to disable building DBPS shared libraries
option(PARQUET_BUILD_DBPS_LIBS "Build DBPS external libraries" ON)
Expand All @@ -305,32 +299,36 @@ if(PARQUET_REQUIRE_ENCRYPTION)
include(ExternalProject)

# Allow callers to inject additional CMake args for DBPS (e.g., BOOST_ROOT)
set(PARQUET_DBPS_CMAKE_ARGS "${PARQUET_DBPS_CMAKE_ARGS}" CACHE STRING "Extra CMake args for DBPS ExternalProject")
set(PARQUET_DBPS_CMAKE_ARGS
"${PARQUET_DBPS_CMAKE_ARGS}"
CACHE STRING "Extra CMake args for DBPS ExternalProject")

#builds DBPS shared libraries alongside Parquet
#same OS, same architecture, same compiler, same build type, same CMake args
ExternalProject_Add(dbps_external
DOWNLOAD_COMMAND "" # disables download, assumes (correctly) that sources are already fetched
SOURCE_DIR ${dbps_agent_SOURCE_DIR}
BINARY_DIR ${dbps_agent_BINARY_DIR}
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DBUILD_SHARED_LIBS=ON
-DBUILD_TESTING=OFF

# Place DBPS outputs next to Arrow artifacts
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${BUILD_OUTPUT_ROOT_DIRECTORY}
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${BUILD_OUTPUT_ROOT_DIRECTORY}
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${BUILD_OUTPUT_ROOT_DIRECTORY}
${PARQUET_DBPS_CMAKE_ARGS}
INSTALL_COMMAND "" #disables install - artifacts already copied to BUILD_OUTPUT_ROOT_DIRECTORY
externalproject_add(dbps_external
DOWNLOAD_COMMAND "" # disables download, assumes (correctly) that sources are already fetched
SOURCE_DIR ${dbps_agent_SOURCE_DIR}
BINARY_DIR ${dbps_agent_BINARY_DIR}
CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DBUILD_SHARED_LIBS=ON
-DBUILD_TESTING=OFF
# Place DBPS outputs next to Arrow artifacts
-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=${BUILD_OUTPUT_ROOT_DIRECTORY}
-DCMAKE_RUNTIME_OUTPUT_DIRECTORY=${BUILD_OUTPUT_ROOT_DIRECTORY}
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${BUILD_OUTPUT_ROOT_DIRECTORY}
${PARQUET_DBPS_CMAKE_ARGS}
INSTALL_COMMAND "" #disables install - artifacts already copied to BUILD_OUTPUT_ROOT_DIRECTORY
)
endif()

list(APPEND PARQUET_SHARED_PRIVATE_LINK_LIBS magic_enum_header_only tcb_span)
list(APPEND PARQUET_STATIC_LINK_LIBS magic_enum_header_only tcb_span)
if(ARROW_TESTING)
list(APPEND PARQUET_TEST_LINK_LIBS magic_enum_header_only tcb_span dbps_interface)
list(APPEND
PARQUET_TEST_LINK_LIBS
magic_enum_header_only
tcb_span
dbps_interface)
endif()
list(APPEND PARQUET_SHARED_PRIVATE_LINK_LIBS dbps_interface)
list(APPEND PARQUET_STATIC_LINK_LIBS dbps_interface)
Expand Down Expand Up @@ -509,7 +507,8 @@ add_parquet_test(arrow-reader-writer-test
arrow/arrow_reader_writer_test.cc
arrow/arrow_statistics_test.cc
arrow/variant_test.cc
$<$<BOOL:${PARQUET_REQUIRE_ENCRYPTION}>:encryption/external/test_utils.cc>)
$<$<BOOL:${PARQUET_REQUIRE_ENCRYPTION}>:encryption/external/test_utils.cc>
)

add_parquet_test(arrow-internals-test SOURCES arrow/path_internal_test.cc
arrow/reconstruct_internal_test.cc)
Expand Down Expand Up @@ -543,9 +542,7 @@ endif()

# Those tests need to use static linking as they access thrift-generated
# symbols which are not exported by parquet.dll on Windows (PARQUET-1420).
add_parquet_test(file_deserialize_test
SOURCES
file_deserialize_test.cc
add_parquet_test(file_deserialize_test SOURCES file_deserialize_test.cc
encryption/external/test_utils.cc)
add_parquet_test(schema_test)

Expand Down
33 changes: 16 additions & 17 deletions cpp/src/parquet/arrow/arrow_reader_writer_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
#include "parquet/test_util.h"

#ifdef PARQUET_REQUIRE_ENCRYPTION
#include "parquet/encryption/external/test_utils.h"
# include "parquet/encryption/external/test_utils.h"
#endif

using arrow::Array;
Expand Down Expand Up @@ -1973,7 +1973,7 @@ TEST(ExternalDbpaConcurrencyTest, FailsWhenUseThreadsTrue) {
ASSERT_OK(b.Finish(&arr));
auto schema = ::arrow::schema({::arrow::field("f0", ::arrow::int32())});
auto table = ::arrow::Table::Make(schema, {arr});

::arrow::util::SecureString column_key(std::string("key1234567890123"));
::arrow::util::SecureString footer_key(std::string("footer_key123456"));

Expand All @@ -1989,31 +1989,30 @@ TEST(ExternalDbpaConcurrencyTest, FailsWhenUseThreadsTrue) {

parquet::ExternalFileEncryptionProperties::Builder fep_builder(footer_key);
fep_builder.footer_key_metadata("kf")
->encrypted_columns(enc_cols)
->algorithm(parquet::ParquetCipher::AES_GCM_V1)
->configuration_properties({{parquet::ParquetCipher::EXTERNAL_DBPA_V1,
{{"agent_library_path", lib_path},
{"file_path", "/tmp/test"}}}});
->encrypted_columns(enc_cols)
->algorithm(parquet::ParquetCipher::AES_GCM_V1)
->configuration_properties(
{{parquet::ParquetCipher::EXTERNAL_DBPA_V1,
{{"agent_library_path", lib_path}, {"file_path", "/tmp/test"}}}});

auto writer_props =
parquet::WriterProperties::Builder().encryption(fep_builder.build_external())->build();
auto writer_props = parquet::WriterProperties::Builder()
.encryption(fep_builder.build_external())
->build();

ASSERT_OK_AND_ASSIGN(
auto sink, ::arrow::io::BufferOutputStream::Create(1 << 16, default_memory_pool()));
ASSERT_OK(parquet::arrow::WriteTable(*table, default_memory_pool(), sink, /*chunk_size=*/1024,
writer_props));
auto sink, ::arrow::io::BufferOutputStream::Create(1 << 16, default_memory_pool()));
ASSERT_OK(parquet::arrow::WriteTable(*table, default_memory_pool(), sink,
/*chunk_size=*/1024, writer_props));
ASSERT_OK_AND_ASSIGN(auto buffer, sink->Finish());

auto kr = std::make_shared<parquet::StringKeyIdRetriever>();
kr->PutKey("kf", footer_key);
kr->PutKey("key1234567890123", column_key);

parquet::ExternalFileDecryptionProperties::Builder dep_builder;
dep_builder.key_retriever(kr)
->app_context("{}")
->configuration_properties({{parquet::ParquetCipher::EXTERNAL_DBPA_V1,
{{"agent_library_path", lib_path},
{"file_path", "/tmp/test"}}}});
dep_builder.key_retriever(kr)->app_context("{}")->configuration_properties(
{{parquet::ParquetCipher::EXTERNAL_DBPA_V1,
{{"agent_library_path", lib_path}, {"file_path", "/tmp/test"}}}});
parquet::ReaderProperties rp = parquet::default_reader_properties();
rp.file_decryption_properties(dep_builder.build_external());

Expand Down
10 changes: 6 additions & 4 deletions cpp/src/parquet/arrow/reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ bool IsExternalDBPAEncryptionUsedInColumns(std::shared_ptr<FileMetaData> metadat
if (column_metadata->crypto_metadata()) {
auto crypto_metadata = column_metadata->crypto_metadata();
if (crypto_metadata->is_encryption_algorithm_set() &&
crypto_metadata->encryption_algorithm().algorithm == ParquetCipher::EXTERNAL_DBPA_V1) {
crypto_metadata->encryption_algorithm().algorithm ==
ParquetCipher::EXTERNAL_DBPA_V1) {
return true;
}
}
Expand All @@ -164,12 +165,13 @@ class FileReaderImpl : public FileReader {
reader_properties_(std::move(properties)) {}

Status Init() {
// If the file is encrypted using EXTERNAL_DBPA_V1 on any of its columns, then it is not safe
// to use multiple threads to read the file.
// If the file is encrypted using EXTERNAL_DBPA_V1 on any of its columns, then it
// is not safe to use multiple threads to read the file.
if (reader_properties_.use_threads()) {
auto metadata = reader_->metadata();
if (IsExternalDBPAEncryptionUsedInColumns(metadata)) {
return Status::Invalid("EXTERNAL_DBPA_V1 encryption does not support multiple threads");
return Status::Invalid(
"EXTERNAL_DBPA_V1 encryption does not support multiple threads");
}
}
return SchemaManifest::Make(reader_->metadata()->schema(),
Expand Down
Loading
Loading