From 3352c2e0fdd09ac144c639b0a0ca569c06505591 Mon Sep 17 00:00:00 2001 From: Volodymyr Yurchenko Date: Fri, 20 Dec 2019 13:05:30 +0100 Subject: [PATCH 1/7] Use libjalien to load the certificate and CAs Signed-off-by: Nikola Hardi --- CCDB/CMakeLists.txt | 1 + CCDB/include/CCDB/CcdbApi.h | 8 ++++ CCDB/src/CcdbApi.cxx | 64 ++++++++++++++++++++++++++++++ dependencies/FindlibjalienO2.cmake | 41 +++++++++++++++++++ dependencies/O2Dependencies.cmake | 3 ++ 5 files changed, 117 insertions(+) create mode 100644 dependencies/FindlibjalienO2.cmake diff --git a/CCDB/CMakeLists.txt b/CCDB/CMakeLists.txt index a91a3aa31347e..3fdd92c57576a 100644 --- a/CCDB/CMakeLists.txt +++ b/CCDB/CMakeLists.txt @@ -18,6 +18,7 @@ o2_add_library(CCDB ROOT::Hist O2::CommonUtils FairMQ::FairMQ + libjalien::libjalienO2 TARGETVARNAME targetName) o2_target_root_dictionary(CCDB diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 8762174394128..fd432e5c1c115 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -23,6 +23,7 @@ #include #include #include "CCDB/CcdbObjectInfo.h" +#include class TFile; class TGrid; @@ -305,6 +306,13 @@ class CcdbApi //: public DatabaseInterface constexpr static const char* CCDBMETA_ENTRY = "ccdb_meta"; constexpr static const char* CCDBOBJECT_ENTRY = "ccdb_object"; + /** + * Set curl SSL options. The client still will be able to connect to non-ssl endpoints + * @param curl curl handler + * @return + */ + static void curlSetSSLOptions(CURL *curl); + private: /** * Initialize in local mode; Objects will be retrieved from snapshot diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index ffe8f4d9bdeec..82337d0e15384 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -174,6 +174,8 @@ void CcdbApi::storeAsBinaryFile(const char* buffer, size_t size, const std::stri curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + curlSetSSLOptions(curl); + /* Perform the request, res will get the return code */ CURLcode res = curl_easy_perform(curl); /* Check for errors */ @@ -300,6 +302,8 @@ static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, voi * @param nmemb * @param userp a MemoryStruct where data is stored. * @return the size of the data we received and stored at userp. + * If an error is returned no attempt to establish a connection is made + * and the perform operation will return the callback's error code */ static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, FILE* stream) { @@ -307,6 +311,48 @@ static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, FILE* st return written; } +/** + * Callback to load credentials and CA's + * @param curl curl handler + * @param ssl_ctx SSL context that will be modified + * @param parm + * @return + */ +static CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *parm) +{ + //(void)curl; + //(void)parm; + + TJAlienSSLContext context; + context.SetCertAndKey((SSL_CTX*) ssl_ctx); + context.SetCAPath((SSL_CTX*) ssl_ctx); + + return CURLE_OK; +} + +void CcdbApi::curlSetSSLOptions(CURL *curl) +{ + // Enable full error reporting + char errbuf[CURL_ERROR_SIZE]; + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); + errbuf[0] = 0; + + // Turn off the default CA locations, otherwise libcurl will load CA + // certificates from the locations that were detected/specified at + // build-time + curl_easy_setopt(curl, CURLOPT_CAINFO, NULL); + curl_easy_setopt(curl, CURLOPT_CAPATH, NULL); + + CURLcode ret = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, *ssl_ctx_callback); + if (ret != CURLE_OK) { + size_t len = strlen(errbuf); + if (len) + fprintf(stderr, "%s%s", errbuf, ((errbuf[len - 1] != '\n') ? "\n" : "")); + else + fprintf(stderr, "curl_easy_setopt() failed: %s\n", curl_easy_strerror(ret)); + } +} + TObject* CcdbApi::retrieve(std::string const& path, std::map const& metadata, long timestamp) const { @@ -342,6 +388,8 @@ TObject* CcdbApi::retrieve(std::string const& path, std::map CcdbApi::retrieveHeaders(std::string const& p curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_map_callback<>); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers); + curlSetSSLOptions(curl); + // Perform the request, res will get the return code res = curl_easy_perform(curl); if (res != CURLE_OK) { @@ -1080,6 +1142,8 @@ bool CcdbApi::getCCDBEntryHeaders(std::string const& url, std::string const& eta curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers); + curlSetSSLOptions(curl); + /* Perform the request */ curl_easy_perform(curl); long http_code = 0; diff --git a/dependencies/FindlibjalienO2.cmake b/dependencies/FindlibjalienO2.cmake new file mode 100644 index 0000000000000..492880efc2110 --- /dev/null +++ b/dependencies/FindlibjalienO2.cmake @@ -0,0 +1,41 @@ +# Find module for libjalienO2. +# Variables: +# - LIBJALIENO2_FOUND: TRUE if found +# - LIBJALIENO2_LIBPATH: library path +# - LIBJALIENO2_INCLUDE_DIR: include dir + +# Init +include(FindPackageHandleStandardArgs) + +# find includes +find_path(LIBJALIENO2_INCLUDE_DIR TJAlienSSLContext.h + PATH_SUFFIXES "include" + HINTS "${LIBJALIENO2}" +) + +mark_as_advanced(LIBJALIENO2_INCLUDE_DIR) + +# find library +find_library(LIBJALIENO2_LIBPATH "jalienO2" + PATH_SUFFIXES "lib" + HINTS "${LIBJALIENO2}" +) + +mark_as_advanced(LIBJALIENO2_LIBPATH) + +find_package_handle_standard_args(libjalienO2 DEFAULT_MSG + LIBJALIENO2_LIBPATH LIBJALIENO2_INCLUDE_DIR) + +if(LIBJALIENO2_FOUND) + set(LIBJALIENO2_LIBRARIES ${LIBJALIENO2_LIBPATH}) + set(LIBJALIENO2_INCLUDE_DIRS ${LIBJALIENO2_INCLUDE_DIR}) + + # add target + if(NOT TARGET libjalien::libjalienO2) + add_library(libjalien::libjalienO2 IMPORTED INTERFACE) + set_target_properties(libjalien::libjalienO2 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${LIBJALIENO2_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${LIBJALIENO2_LIBPATH}" + ) + endif() +endif() diff --git a/dependencies/O2Dependencies.cmake b/dependencies/O2Dependencies.cmake index fce21860c9917..0c619dfa92c90 100644 --- a/dependencies/O2Dependencies.cmake +++ b/dependencies/O2Dependencies.cmake @@ -109,6 +109,9 @@ set_package_properties(JAliEnROOT PROPERTIES TYPE RECOMMENDED) find_package(XRootD MODULE) set_package_properties(XRootD PROPERTIES TYPE RECOMMENDED) +find_package(libjalienO2 MODULE) +set_package_properties(libjalienO2 PROPERTIES TYPE REQUIRED PURPOSE "For CCDB API") + # MC specific packages message(STATUS "Input BUILD_SIMULATION=${BUILD_SIMULATION}") include("${CMAKE_CURRENT_LIST_DIR}/O2SimulationDependencies.cmake") From e13f187342292345c793bc4fd743dfae4d3298c9 Mon Sep 17 00:00:00 2001 From: Nikola Hardi Date: Wed, 24 Feb 2021 13:52:57 +0100 Subject: [PATCH 2/7] Add the credentials manager --- CCDB/include/CCDB/CcdbApi.h | 3 ++- CCDB/src/CcdbApi.cxx | 49 +++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index fd432e5c1c115..2ab5bc8049ce5 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -311,7 +311,7 @@ class CcdbApi //: public DatabaseInterface * @param curl curl handler * @return */ - static void curlSetSSLOptions(CURL *curl); + void curlSetSSLOptions(CURL *curl) const; private: /** @@ -420,6 +420,7 @@ class CcdbApi //: public DatabaseInterface bool mInSnapshotMode = false; mutable TGrid* mAlienInstance = nullptr; // a cached connection to TGrid (needed for Alien locations) bool mHaveAlienToken = false; // stores if an alien token is available + TJAlienCredentials mJAlienCredentials{}; // access JAliEn credentials ClassDefNV(CcdbApi, 1); }; diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index 82337d0e15384..feec2fc372e80 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -320,37 +320,31 @@ static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, FILE* st */ static CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *parm) { - //(void)curl; - //(void)parm; - - TJAlienSSLContext context; - context.SetCertAndKey((SSL_CTX*) ssl_ctx); - context.SetCAPath((SSL_CTX*) ssl_ctx); - + cout << "Curl SSL callback" << endl; return CURLE_OK; } -void CcdbApi::curlSetSSLOptions(CURL *curl) +void CcdbApi::curlSetSSLOptions(CURL *curl_handle) const { - // Enable full error reporting - char errbuf[CURL_ERROR_SIZE]; - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf); - errbuf[0] = 0; - - // Turn off the default CA locations, otherwise libcurl will load CA - // certificates from the locations that were detected/specified at - // build-time - curl_easy_setopt(curl, CURLOPT_CAINFO, NULL); - curl_easy_setopt(curl, CURLOPT_CAPATH, NULL); - - CURLcode ret = curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, *ssl_ctx_callback); - if (ret != CURLE_OK) { - size_t len = strlen(errbuf); - if (len) - fprintf(stderr, "%s%s", errbuf, ((errbuf[len - 1] != '\n') ? "\n" : "")); - else - fprintf(stderr, "curl_easy_setopt() failed: %s\n", curl_easy_strerror(ret)); + CredentialsKind cmk = getAutoCreds(mJAlienCredentials, msg); + + /* NOTE: return early, the warning should be printed on SSL callback if needed */ + if(cmk == cNOT_FOUND) { + return; } + + TJAlienCredentialsObject cmo = mJAlienCredentials.get(cmk); + + string CAPath = getenv("X509_CERT_DIR"); + curl_easy_setopt(curl_handle, CURLOPT_CAPATH, CAPath.c_str()); + curl_easy_setopt(curl_handle, CURLOPT_CAINFO, nullptr); + curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, cmo.certpath.c_str()); + curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, cmo.keypath.c_str()); + + // NOTE: for lazy logging only + curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback); + + // CURLcode ret = curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, *ssl_ctx_callback); } TObject* CcdbApi::retrieve(std::string const& path, std::map const& metadata, @@ -367,6 +361,9 @@ TObject* CcdbApi::retrieve(std::string const& path, std::map Date: Thu, 25 Feb 2021 17:39:03 +0100 Subject: [PATCH 3/7] JAliEn credentials manager improvements --- CCDB/include/CCDB/CcdbApi.h | 15 ++++++++++----- CCDB/src/CcdbApi.cxx | 25 +++++++++++++++++++++---- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 2ab5bc8049ce5..736973e19bea8 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -23,7 +23,12 @@ #include #include #include "CCDB/CcdbObjectInfo.h" -#include + +#if !defined(__CINT__) && !defined(__MAKECINT__) && !defined(__ROOTCLING__) && !defined(__CLING__) +#include +#else +class TJAlienCredentials; +#endif class TFile; class TGrid; @@ -311,7 +316,7 @@ class CcdbApi //: public DatabaseInterface * @param curl curl handler * @return */ - void curlSetSSLOptions(CURL *curl) const; + static void curlSetSSLOptions(CURL *curl); private: /** @@ -418,9 +423,9 @@ class CcdbApi //: public DatabaseInterface std::string mUrl{}; std::string mSnapshotTopPath{}; bool mInSnapshotMode = false; - mutable TGrid* mAlienInstance = nullptr; // a cached connection to TGrid (needed for Alien locations) - bool mHaveAlienToken = false; // stores if an alien token is available - TJAlienCredentials mJAlienCredentials{}; // access JAliEn credentials + mutable TGrid* mAlienInstance = nullptr; // a cached connection to TGrid (needed for Alien locations) + bool mHaveAlienToken = false; // stores if an alien token is available + static std::unique_ptr mJAlienCredentials; // access JAliEn credentials ClassDefNV(CcdbApi, 1); }; diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index feec2fc372e80..9bcfd3fa7ba92 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -48,6 +48,7 @@ namespace ccdb using namespace std; std::mutex gIOMutex; // to protect TMemFile IO operations +unique_ptr CcdbApi::mJAlienCredentials = nullptr; CcdbApi::~CcdbApi() { @@ -58,6 +59,9 @@ void CcdbApi::curlInit() { // todo : are there other things to initialize globally for curl ? curl_global_init(CURL_GLOBAL_DEFAULT); + CcdbApi::mJAlienCredentials.reset(new TJAlienCredentials()); + CcdbApi::mJAlienCredentials->loadCredentials(); + CcdbApi::mJAlienCredentials->selectPreferedCredentials(); } void CcdbApi::init(std::string const& host) @@ -320,20 +324,32 @@ static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, FILE* st */ static CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *parm) { - cout << "Curl SSL callback" << endl; + std::string msg((const char*)parm); + int start = 0, end = msg.find('\n'); + + if(msg.length() > 0 && end == -1) { + LOG(WARN) << msg; + } + else if (end > 0) { + while(end > 0) { + LOG(WARN) << msg.substr(start, end-start); + start = end+1; + end = msg.find('\n', start); + } + } return CURLE_OK; } -void CcdbApi::curlSetSSLOptions(CURL *curl_handle) const +void CcdbApi::curlSetSSLOptions(CURL *curl_handle) { - CredentialsKind cmk = getAutoCreds(mJAlienCredentials, msg); + CredentialsKind cmk = mJAlienCredentials->getPreferedCredentials(); /* NOTE: return early, the warning should be printed on SSL callback if needed */ if(cmk == cNOT_FOUND) { return; } - TJAlienCredentialsObject cmo = mJAlienCredentials.get(cmk); + TJAlienCredentialsObject cmo = mJAlienCredentials->get(cmk); string CAPath = getenv("X509_CERT_DIR"); curl_easy_setopt(curl_handle, CURLOPT_CAPATH, CAPath.c_str()); @@ -343,6 +359,7 @@ void CcdbApi::curlSetSSLOptions(CURL *curl_handle) const // NOTE: for lazy logging only curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback); + curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_DATA, mJAlienCredentials->getMessages().c_str()); // CURLcode ret = curl_easy_setopt(curl_handle, CURLOPT_SSL_CTX_FUNCTION, *ssl_ctx_callback); } From 7f114613f8ca45106a2265e454e152fb94311faa Mon Sep 17 00:00:00 2001 From: Nikola Hardi Date: Mon, 29 Mar 2021 15:12:47 +0200 Subject: [PATCH 4/7] Enable redirection on upload in CcdbApi --- CCDB/src/CcdbApi.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index 9bcfd3fa7ba92..1b23a7d6b0de9 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -177,6 +177,7 @@ void CcdbApi::storeAsBinaryFile(const char* buffer, size_t size, const std::stri curl_easy_setopt(curl, CURLOPT_URL, fullUrl.c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curlSetSSLOptions(curl); From 55f7e2dad6c2372799fdddaf6103959d3ff2dcf4 Mon Sep 17 00:00:00 2001 From: Nikola Hardi Date: Tue, 30 Mar 2021 14:36:04 +0200 Subject: [PATCH 5/7] Include clang-format formattig updates --- CCDB/include/CCDB/CcdbApi.h | 2 +- CCDB/src/CcdbApi.cxx | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 736973e19bea8..934a9ecc36d58 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -316,7 +316,7 @@ class CcdbApi //: public DatabaseInterface * @param curl curl handler * @return */ - static void curlSetSSLOptions(CURL *curl); + static void curlSetSSLOptions(CURL* curl); private: /** diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index 1b23a7d6b0de9..12dddcc3b2ed6 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -323,30 +323,29 @@ static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, FILE* st * @param parm * @return */ -static CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *parm) +static CURLcode ssl_ctx_callback(CURL* curl, void* ssl_ctx, void* parm) { std::string msg((const char*)parm); int start = 0, end = msg.find('\n'); - if(msg.length() > 0 && end == -1) { - LOG(WARN) << msg; - } - else if (end > 0) { - while(end > 0) { - LOG(WARN) << msg.substr(start, end-start); - start = end+1; + if (msg.length() > 0 && end == -1) { + LOG(WARN) << msg; + } else if (end > 0) { + while (end > 0) { + LOG(WARN) << msg.substr(start, end - start); + start = end + 1; end = msg.find('\n', start); } } return CURLE_OK; } -void CcdbApi::curlSetSSLOptions(CURL *curl_handle) +void CcdbApi::curlSetSSLOptions(CURL* curl_handle) { CredentialsKind cmk = mJAlienCredentials->getPreferedCredentials(); /* NOTE: return early, the warning should be printed on SSL callback if needed */ - if(cmk == cNOT_FOUND) { + if (cmk == cNOT_FOUND) { return; } @@ -381,7 +380,6 @@ TObject* CcdbApi::retrieve(std::string const& path, std::map Date: Wed, 26 May 2021 13:52:13 +0200 Subject: [PATCH 6/7] Add new methods to header This should fix compilation errors. --- CCDB/include/CCDB/CcdbApi.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CCDB/include/CCDB/CcdbApi.h b/CCDB/include/CCDB/CcdbApi.h index 07375e94bd7e9..18d208427738d 100644 --- a/CCDB/include/CCDB/CcdbApi.h +++ b/CCDB/include/CCDB/CcdbApi.h @@ -289,6 +289,12 @@ class CcdbApi //: public DatabaseInterface */ static void curlSetSSLOptions(CURL* curl); + TObject* retrieve(std::string const& path, std::map const& metadata, long timestamp) const; + + TObject* retrieveFromTFile(std::string const& path, std::map const& metadata, long timestamp, + std::map* headers, std::string const& etag, + const std::string& createdNotAfter, const std::string& createdNotBefore) const; + private: /** * Initialize in local mode; Objects will be retrieved from snapshot From 97c98ad738b04a81e08f4228c8ede653d0baa994 Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Wed, 26 May 2021 21:03:43 +0200 Subject: [PATCH 7/7] Fix more build errors --- CCDB/src/CcdbApi.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CCDB/src/CcdbApi.cxx b/CCDB/src/CcdbApi.cxx index fffa7bf98445b..b120aaa7b2aa4 100644 --- a/CCDB/src/CcdbApi.cxx +++ b/CCDB/src/CcdbApi.cxx @@ -552,7 +552,7 @@ TObject* CcdbApi::retrieveFromTFile(std::string const& path, std::map