diff --git a/include/davix/params/davix_request_params_types.hpp b/include/davix/params/davix_request_params_types.hpp index cd0abcbb..9bf7d443 100644 --- a/include/davix/params/davix_request_params_types.hpp +++ b/include/davix/params/davix_request_params_types.hpp @@ -58,7 +58,9 @@ namespace RequestProtocol{ // Use gcloud API Gcloud, // Use Swift API - Swift + Swift, + // Use CS3 API + CS3 }; } @@ -121,6 +123,11 @@ typedef std::string AwsRegion; /// typedef std::string AwsToken; +/// +/// \brief string for Reva security token +/// +typedef std::string RevaToken; + /// /// \brief string for Azure private key /// diff --git a/include/davix/params/davixrequestparams.hpp b/include/davix/params/davixrequestparams.hpp index 898f429c..05043822 100644 --- a/include/davix/params/davixrequestparams.hpp +++ b/include/davix/params/davixrequestparams.hpp @@ -24,6 +24,7 @@ #include #include +#include #include "davix_request_params_types.hpp" #include "../auth/davixauth.hpp" @@ -47,6 +48,12 @@ namespace gcloud { class Credentials; } +namespace reva { + class Credentials; + struct Credential; + typedef std::map CredentialMap; +} + struct RequestParamsInternal; @@ -160,6 +167,31 @@ class DAVIX_EXPORT RequestParams /// const AwsToken & getAwsToken() const; + /// + /// \brief define the Reva Credentials + /// \param credentials credential map of type reva::Credential + /// + void setRevaCredentials(Davix::reva::Credentials & credentials); + + /// + /// \brief get Reva Token + /// \return reva token of type std::string + /// + const RevaToken getRevaToken(std::string uri) const&; + + /// + /// \brief get Reva Credentials + /// \return credential map of type std::map CredentialMap + /// \n Credential consists of a RevaToken and a write_access flag + /// + const Davix::reva::Credentials & getRevaCredentials() const; + + /// + /// \brief get Reva Credentials + /// \return credentials type reva::Credential + /// + void getRevaCredentialMap(Davix::reva::CredentialMap & cmap); + /// /// \brief set whether we're using an S3 path-based url /// \param alternate whether using an S3 path-based url diff --git a/include/davix/status/davixstatusrequest.hpp b/include/davix/status/davixstatusrequest.hpp index f259987d..e42a7115 100644 --- a/include/davix/status/davixstatusrequest.hpp +++ b/include/davix/status/davixstatusrequest.hpp @@ -155,6 +155,9 @@ enum Code { /// Insufficient storage InsufficientStorage = 0x27, + /// Environment Variable Missing + EnvVarNotSet = 0x28, + /// Undefined error UnknowError = 0x100 diff --git a/include/davix/utils/davix_cs3_utils.hpp b/include/davix/utils/davix_cs3_utils.hpp new file mode 100644 index 00000000..0297b7cd --- /dev/null +++ b/include/davix/utils/davix_cs3_utils.hpp @@ -0,0 +1,59 @@ +#ifndef DAVIX_CS3_UTILS_HPP +#define DAVIX_CS3_UTILS_HPP + +#include +#include + +namespace Davix { +namespace reva { + +struct Credential { + RevaToken token; + bool token_write_access; +}; + +typedef std::map CredentialMap; + +//creates a deep copy of CredentialMap + +/// +/// @class Credentials +/// @brief Reva credentials +/// +/// Reva credentials +class DAVIX_EXPORT Credentials { +public: + Credentials(); + + bool isEmpty() const; + RevaToken getToken(std::string uri) const&; + void getCredentialMap(CredentialMap &cmap) const; + void addCredentials(std::string uri, std::string token, bool token_write_access); + + Credentials(const Credentials&); // Copy constructor + Credentials(Credentials&&); // Move constructor + Credentials& operator=(const Credentials&); // Copy assignment operator + Credentials& operator=(Credentials&&); // Move assignment operator + virtual ~Credentials(); // Destructor + +private: + CredentialMap *credMap; +}; + + +/// +/// @class CredentialProvider +/// @brief Reva credential provider +/// +/// Reva credential provider +class DAVIX_EXPORT CredentialProvider{ +public: + CredentialProvider(){}; + void updateCredentials(Credentials &creds, std::string uri, bool token_write_access); +}; + + +}//Reva +}//Davix + +#endif //DAVIX_CS3_UTILS_HPP diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67d8a766..79a8858b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,6 +60,7 @@ set(DAVIX_SOURCES utils/davix_gcloud_utils.cpp utils/davix_logger_internal.hpp utils/davix_logger.cpp utils/davix_misc_utils.cpp + utils/davix_cs3_utils.cpp utils/davix_utils_internal.hpp utils/davix_s3_utils.cpp utils/davix_swift_utils.cpp utils/simple_get_pass.h utils/simple_get_pass.cpp diff --git a/src/backend/BackendRequest.cpp b/src/backend/BackendRequest.cpp index 53842374..7977280a 100644 --- a/src/backend/BackendRequest.cpp +++ b/src/backend/BackendRequest.cpp @@ -22,6 +22,7 @@ #include "BackendRequest.hpp" #include #include +#include #include #include #include @@ -134,6 +135,58 @@ void BackendRequest::configureSwiftParams() { _current.reset(new Uri(signed_url)); } + //------------------------------------------------------------------------------ + // Configure request for Reva. + //------------------------------------------------------------------------------ + void BackendRequest::configureRevaParams() + { + std::string uri = getOriginalUri()->getString(); + + if (_request_type != "COPY") { + std::string token = _params.getRevaToken(uri); + if (token != ""){ + _headers_field.emplace_back("X-Access-Token", token); + } + } + else { + reva::CredentialMap cmap; + _params.getRevaCredentialMap(cmap); + + //In pull mode : Dst = Active Endpoint and Src = Passive Endpoint + //In push mode : Dst = Passive Endpoint and Src = Active Endpoint + std::string active_token, passive_token; + + //In pull mode original uri = destination uri + if(_params.getCopyMode() == Davix::CopyMode::Pull){ + for (reva::CredentialMap::iterator itr = cmap.begin(); itr != cmap.end(); ++itr) { + if(itr->second.token_write_access){ + active_token = itr->second.token; + } + else{ + passive_token = itr->second.token; + } + } + } + + //In push mode original uri = src uri + else if(_params.getCopyMode() == Davix::CopyMode::Push){ + for (reva::CredentialMap::iterator itr = cmap.begin(); itr != cmap.end(); ++itr) { + if(itr->second.token_write_access){ + passive_token = itr->second.token; + } + else{ + active_token = itr->second.token; + } + } + } + + _headers_field.emplace_back("X-Access-Token", active_token); + _headers_field.emplace_back("TransferHeaderX-Access-Token", passive_token); + + } + } + + //------------------------------------------------------------------------------ // Set-up deadline, but only if uninitialized //------------------------------------------------------------------------------ diff --git a/src/backend/BackendRequest.hpp b/src/backend/BackendRequest.hpp index 76a73812..417f96fb 100644 --- a/src/backend/BackendRequest.hpp +++ b/src/backend/BackendRequest.hpp @@ -219,6 +219,11 @@ class BackendRequest { //---------------------------------------------------------------------------- void configureSwiftParams(); + //---------------------------------------------------------------------------- + // Configure request for Reva. + //---------------------------------------------------------------------------- + void configureRevaParams(); + //---------------------------------------------------------------------------- // Set-up deadline, but only if uninitialized //---------------------------------------------------------------------------- diff --git a/src/backend/SessionFactory.cpp b/src/backend/SessionFactory.cpp index dbf8ae8d..2d9dac37 100644 --- a/src/backend/SessionFactory.cpp +++ b/src/backend/SessionFactory.cpp @@ -78,7 +78,8 @@ std::string SessionFactory::httpizeProtocol(const std::string &protocol) { proto.compare(0,2, "s3") == 0 || proto.compare(0,3, "dav") == 0 || proto.compare(0, 6, "gcloud") == 0 || - proto.compare(0, 5, "swift") == 0){ + proto.compare(0, 5, "swift") == 0 || + proto.compare(0, 3, "cs3") == 0){ proto.assign("http"); diff --git a/src/modules/copy/copy.cpp b/src/modules/copy/copy.cpp index 406cb814..9b679cc3 100644 --- a/src/modules/copy/copy.cpp +++ b/src/modules/copy/copy.cpp @@ -224,6 +224,10 @@ void DavixCopyInternal::copy(const Uri &src, const Uri &dst, destination.replace(0, 3, "http"); } + if(destination.compare(0, 3, "cs3") == 0){ + destination.replace(0, 3, "http"); + } + // Perform COPY hopping through redirections HttpRequest* request = NULL; do { diff --git a/src/neon/neonrequest.cpp b/src/neon/neonrequest.cpp index 4768d2d3..41fadeae 100644 --- a/src/neon/neonrequest.cpp +++ b/src/neon/neonrequest.cpp @@ -52,6 +52,8 @@ void configureRequestParamsProto(const Uri &uri, RequestParams ¶ms){ params.setProtocol(RequestProtocol::Webdav); }else if ( proto.compare(0, 6, "gcloud") ==0) { params.setProtocol(RequestProtocol::Gcloud); + }else if (proto.compare(0, 3, "cs3")==0){ + params.setProtocol(RequestProtocol::CS3); } } } @@ -151,6 +153,9 @@ void NeonRequest::prepareUriParams() { // configure swift params if needed if(_params.getProtocol() == RequestProtocol::Swift) configureSwiftParams(); + + if(_params.getProtocol() == RequestProtocol::CS3) + configureRevaParams(); } //------------------------------------------------------------------------------ diff --git a/src/params/davixrequestparams.cpp b/src/params/davixrequestparams.cpp index c0ab1372..8a6ed5d3 100644 --- a/src/params/davixrequestparams.cpp +++ b/src/params/davixrequestparams.cpp @@ -25,6 +25,7 @@ #include #include #include +#include @@ -99,6 +100,7 @@ struct RequestParamsInternal{ _aws_cred(), _aws_region(), _aws_token(), + _reva_creds(), _aws_alternate(false), _azure_key(), _gcloud_creds(), @@ -151,6 +153,7 @@ struct RequestParamsInternal{ _aws_cred(param_private._aws_cred), _aws_region(param_private._aws_region), _aws_token(param_private._aws_token), + _reva_creds(param_private._reva_creds), _aws_alternate(param_private._aws_alternate), _azure_key(param_private._azure_key), _gcloud_creds(param_private._gcloud_creds), @@ -202,6 +205,7 @@ struct RequestParamsInternal{ std::pair _aws_cred; AwsRegion _aws_region; AwsToken _aws_token; + reva::Credentials _reva_creds; bool _aws_alternate; AzureSecretKey _azure_key; gcloud::Credentials _gcloud_creds; @@ -393,6 +397,21 @@ const AwsToken & RequestParams::getAwsToken() const { return d_ptr->_aws_token; } +void RequestParams::setRevaCredentials(reva::Credentials &credentials) { + d_ptr->_reva_creds = credentials; +} +void RequestParams::getRevaCredentialMap(reva::CredentialMap & cmap) { + d_ptr->_reva_creds.getCredentialMap(cmap); +} + +const RevaToken RequestParams::getRevaToken(std::string uri) const& { + return d_ptr->_reva_creds.getToken(uri); +} + +const reva::Credentials & RequestParams::getRevaCredentials() const { + return d_ptr->_reva_creds; +} + void RequestParams::setAwsAlternate(const bool &alternate) { d_ptr->_aws_alternate = alternate; } diff --git a/src/utils/davix_cs3_utils.cpp b/src/utils/davix_cs3_utils.cpp new file mode 100644 index 00000000..e88516f5 --- /dev/null +++ b/src/utils/davix_cs3_utils.cpp @@ -0,0 +1,116 @@ +#include +#include + +namespace Davix{ +namespace reva { + +// +// Credential +// + +// Constructor +Credentials::Credentials() { + credMap = new CredentialMap(); +} + +// Destructor +Credentials::~Credentials() { + delete credMap; + credMap = NULL; +} + +// Copy constructor +Credentials::Credentials(const Credentials& other) { + credMap = new CredentialMap(*other.credMap); +} + +// Move constructor +Credentials::Credentials(Credentials&& other) { + credMap = other.credMap; + other.credMap = new CredentialMap(); +} + +// Copy assignment operator +Credentials& Credentials::operator=(const Credentials& other) { + credMap = new CredentialMap(*other.credMap); + return *this; +} + +// Move assignment operator +Credentials& Credentials::operator=(Credentials&& other) { + credMap = other.credMap; + other.credMap = new CredentialMap(); + return *this; +} + +bool Credentials::isEmpty() const { + return credMap->empty(); +} + +RevaToken Credentials::getToken(std::string uri) const&{ + std::string tkn = ""; + if(credMap->find(uri) != credMap->end()){ + tkn = (*credMap)[uri].token; + } + return tkn; +} + +void Credentials::getCredentialMap(CredentialMap & cmap) const { + for (CredentialMap::iterator itr = credMap->begin(); itr != credMap->end(); ++itr) { + Credential c {itr->second.token, itr->second.token_write_access}; + cmap.emplace(itr->first,c); + } +} + +void Credentials::addCredentials(std::string uri, std::string token, bool token_write_access){ + + if(credMap->find(uri) == credMap->end()){ + Credential cred {token, token_write_access}; + credMap->emplace(uri, cred); + } +} + + +// Helper function +// To convert char* to string safely +std::string getEnvStr(std::string var){ + char* val = getenv(var.c_str()); + return val == NULL ? std::string() : std::string(val); +} + +// +// Credential Provider +// + +void CredentialProvider::updateCredentials(Credentials &creds, std::string uri, bool token_write_access){ + + //Assuming urls with +3rd prefix have been deprecated + + std::string src_url, dst_url, token; + + src_url = getEnvStr("SRC_URL"); + dst_url = getEnvStr("DST_URL"); + + // Src and Dst env var need to be set as env var for the time being + // This will be removed in the future + + if (src_url == "" || dst_url == ""){ + throw DavixException(std::string("davix::reva"), StatusCode::EnvVarNotSet, "Source or Destination variable is not set"); + } + + // If any required token is not set we get an empty string + // When this happens copy fails with Authentication error + + if(uri.compare(dst_url) <= 0 ){ + token = getEnvStr("REVA_DST_TOKEN"); + } + else if (uri.compare(src_url) <= 0 ){ + token = getEnvStr("REVA_SRC_TOKEN"); + } + + creds.addCredentials(uri, token, token_write_access); + +} + +} //reva +} //Davix diff --git a/src/utils/davixuri.cpp b/src/utils/davixuri.cpp index 1ebcb500..783cd5f5 100644 --- a/src/utils/davixuri.cpp +++ b/src/utils/davixuri.cpp @@ -233,10 +233,10 @@ void Uri::setProtocol(const std::string & protocol) { } void Uri::httpizeProtocol() { - if(d_ptr->proto == "s3" || d_ptr->proto == "dav" || d_ptr->proto == "gcloud" || d_ptr->proto == "swift") { + if(d_ptr->proto == "s3" || d_ptr->proto == "dav" || d_ptr->proto == "gcloud" || d_ptr->proto == "swift" || d_ptr->proto == "cs3") { setProtocol("http"); } - if(d_ptr->proto == "s3s" || d_ptr->proto == "davs" || d_ptr->proto == "gclouds" || d_ptr->proto == "swifts") { + if(d_ptr->proto == "s3s" || d_ptr->proto == "davs" || d_ptr->proto == "gclouds" || d_ptr->proto == "swifts" || d_ptr->proto == "cs3s") { setProtocol("https"); } }