diff --git a/CMakeLists.txt b/CMakeLists.txt index 686aabe9cc..d0b2557078 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,7 @@ endif() add_subdirectory(tools) add_subdirectory(contrib/libs) add_subdirectory(library/cpp) +add_subdirectory(include/ydb-cpp-sdk/client) add_subdirectory(src) add_subdirectory(util) diff --git a/include/ydb-cpp-sdk/client/CMakeLists.txt b/include/ydb-cpp-sdk/client/CMakeLists.txt new file mode 100644 index 0000000000..631efeb3ed --- /dev/null +++ b/include/ydb-cpp-sdk/client/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(iam/common) diff --git a/include/ydb-cpp-sdk/client/iam/common/CMakeLists.txt b/include/ydb-cpp-sdk/client/iam/common/CMakeLists.txt new file mode 100644 index 0000000000..667ae4bd63 --- /dev/null +++ b/include/ydb-cpp-sdk/client/iam/common/CMakeLists.txt @@ -0,0 +1,10 @@ +_ydb_sdk_add_library(client-iam-types INTERFACE) + +target_link_libraries(client-iam-types + INTERFACE + client-ydb_types-credentials + library-jwt + yutil +) + +_ydb_sdk_install_targets(client-iam-types) diff --git a/include/ydb-cpp-sdk/client/iam/common/types.h b/include/ydb-cpp-sdk/client/iam/common/types.h new file mode 100644 index 0000000000..0f1cc384d9 --- /dev/null +++ b/include/ydb-cpp-sdk/client/iam/common/types.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +#include + +#include +#include + +namespace NYdb { + +namespace NIam { + +constexpr std::string_view DEFAULT_ENDPOINT = "iam.api.cloud.yandex.net"; +constexpr bool DEFAULT_ENABLE_SSL = true; + +constexpr std::string_view DEFAULT_HOST = "169.254.169.254"; +constexpr uint32_t DEFAULT_PORT = 80; + +constexpr TDuration DEFAULT_REFRESH_PERIOD = TDuration::Hours(1); +constexpr TDuration DEFAULT_REQUEST_TIMEOUT = TDuration::Seconds(10); + +} + +struct TIamHost { + std::string Host = std::string(NIam::DEFAULT_HOST); + uint32_t Port = NIam::DEFAULT_PORT; + TDuration RefreshPeriod = NIam::DEFAULT_REFRESH_PERIOD; +}; + +struct TIamEndpoint { + std::string Endpoint = std::string(NIam::DEFAULT_ENDPOINT); + TDuration RefreshPeriod = NIam::DEFAULT_REFRESH_PERIOD; + TDuration RequestTimeout = NIam::DEFAULT_REQUEST_TIMEOUT; + bool EnableSsl = NIam::DEFAULT_ENABLE_SSL; +}; + +struct TIamJwtFilename : TIamEndpoint { std::string JwtFilename; }; + +struct TIamJwtContent : TIamEndpoint { std::string JwtContent; }; + +struct TIamJwtParams : TIamEndpoint { TJwtParams JwtParams; }; + +struct TIamOAuth : TIamEndpoint { std::string OAuthToken; }; + + +inline TJwtParams ReadJwtKeyFile(const std::string& filename) { + std::ifstream input(filename, std::ios::in); + return ParseJwtParams({std::istreambuf_iterator(input), std::istreambuf_iterator()}); +} + +} diff --git a/include/ydb-cpp-sdk/client/iam/iam.h b/include/ydb-cpp-sdk/client/iam/iam.h index c2e7d53bc4..a79c200dc7 100644 --- a/include/ydb-cpp-sdk/client/iam/iam.h +++ b/include/ydb-cpp-sdk/client/iam/iam.h @@ -1,3 +1,19 @@ #pragma once -#include "common/iam.h" +#include "common/types.h" + +namespace NYdb { + +/// Acquire an IAM token using a local metadata service on a virtual machine. +TCredentialsProviderFactoryPtr CreateIamCredentialsProviderFactory(const TIamHost& params = {}); + +/// Acquire an IAM token using a JSON Web Token (JWT) file name. +TCredentialsProviderFactoryPtr CreateIamJwtFileCredentialsProviderFactory(const TIamJwtFilename& params); + +/// Acquire an IAM token using JSON Web Token (JWT) contents. +TCredentialsProviderFactoryPtr CreateIamJwtParamsCredentialsProviderFactory(const TIamJwtContent& param); + +// Acquire an IAM token using a user OAuth token. +TCredentialsProviderFactoryPtr CreateIamOAuthCredentialsProviderFactory(const TIamOAuth& params); + +} diff --git a/include/ydb-cpp-sdk/client/iam_private/iam.h b/include/ydb-cpp-sdk/client/iam_private/iam.h index 3bdc3038cb..3b2d742d16 100644 --- a/include/ydb-cpp-sdk/client/iam_private/iam.h +++ b/include/ydb-cpp-sdk/client/iam_private/iam.h @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace NYdb { diff --git a/src/client/helpers/CMakeLists.txt b/src/client/helpers/CMakeLists.txt index cb1ad20393..dc47a456af 100644 --- a/src/client/helpers/CMakeLists.txt +++ b/src/client/helpers/CMakeLists.txt @@ -4,7 +4,7 @@ target_link_libraries(client-helpers PUBLIC yutil client-ydb_types-credentials-oauth2 - client-iam-common + client-iam client-ydb_types-credentials ) diff --git a/src/client/helpers/helpers.cpp b/src/client/helpers/helpers.cpp index 325e04390b..10fcb366ed 100644 --- a/src/client/helpers/helpers.cpp +++ b/src/client/helpers/helpers.cpp @@ -1,6 +1,6 @@ #include -#include +#include #include #include diff --git a/src/client/iam/CMakeLists.txt b/src/client/iam/CMakeLists.txt index 98e6fa5e6f..4dd6d70785 100644 --- a/src/client/iam/CMakeLists.txt +++ b/src/client/iam/CMakeLists.txt @@ -2,14 +2,19 @@ add_subdirectory(common) _ydb_sdk_add_library(client-iam) -target_link_libraries(client-iam PUBLIC - yutil - api-client-yc_public - client-iam-common +target_link_libraries(client-iam + PUBLIC + client-iam-types + yutil + PRIVATE + api-client-yc_public + client-iam-common + json + http-simple ) -_ydb_sdk_install_targets(TARGETS client-iam) - target_sources(client-iam PRIVATE iam.cpp ) + +_ydb_sdk_make_client_component(Iam client-iam) diff --git a/src/client/iam/common/CMakeLists.txt b/src/client/iam/common/CMakeLists.txt index 095c45f9ed..2d50e166c4 100644 --- a/src/client/iam/common/CMakeLists.txt +++ b/src/client/iam/common/CMakeLists.txt @@ -1,17 +1,11 @@ -_ydb_sdk_add_library(client-iam-common) +_ydb_sdk_add_library(client-iam-common INTERFACE) -target_link_libraries(client-iam-common PUBLIC - yutil - grpc-client - http-simple - json - library-jwt - client-ydb_types-credentials - api-client-yc_public +target_link_libraries(client-iam-common + INTERFACE + client-iam-types + grpc-client + threading-future + yutil ) -target_sources(client-iam-common PRIVATE - iam.cpp -) - -_ydb_sdk_make_client_component(Iam client-iam-common) +_ydb_sdk_install_targets(client-iam-common) diff --git a/src/client/iam/common/iam.cpp b/src/client/iam/common/iam.cpp deleted file mode 100644 index 4b42354595..0000000000 --- a/src/client/iam/common/iam.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include - -#include - -#include -#include -#include - -using namespace NYdbGrpc; -using namespace yandex::cloud::iam::v1; - -namespace NYdb { - -class TIAMCredentialsProvider : public ICredentialsProvider { -public: - TIAMCredentialsProvider(const TIamHost& params) - : HttpClient_(TSimpleHttpClient(TString(params.Host), params.Port)) - , Request_("/computeMetadata/v1/instance/service-accounts/default/token") - , NextTicketUpdate_(TInstant::Zero()) - , RefreshPeriod_(params.RefreshPeriod) - { - GetTicket(); - } - - std::string GetAuthInfo() const override { - if (TInstant::Now() >= NextTicketUpdate_) { - GetTicket(); - } - return Ticket_; - } - - bool IsValid() const override { - return true; - } - -private: - TSimpleHttpClient HttpClient_; - std::string Request_; - mutable std::string Ticket_; - mutable TInstant NextTicketUpdate_; - TDuration RefreshPeriod_; - - void GetTicket() const { - try { - TStringStream out; - TSimpleHttpClient::THeaders headers; - headers["Metadata-Flavor"] = "Google"; - HttpClient_.DoGet(Request_, &out, headers); - NJson::TJsonValue resp; - NJson::ReadJsonTree(&out, &resp, true); - - auto respMap = resp.GetMap(); - - if (auto it = respMap.find("access_token"); it == respMap.end()) - ythrow yexception() << "Result doesn't contain access_token"; - else if (std::string ticket = it->second.GetStringSafe(); ticket.empty()) - ythrow yexception() << "Got empty ticket"; - else - Ticket_ = std::move(ticket); - - if (auto it = respMap.find("expires_in"); it == respMap.end()) - ythrow yexception() << "Result doesn't contain expires_in"; - else { - const TDuration expiresIn = TDuration::Seconds(it->second.GetUInteger()) / 2; - - const auto interval = std::max(std::min(expiresIn, RefreshPeriod_), TDuration::MilliSeconds(100)); - - NextTicketUpdate_ = TInstant::Now() + interval; - } - } catch (...) { - } - } -}; - - -class TIamCredentialsProviderFactory : public ICredentialsProviderFactory { -public: - TIamCredentialsProviderFactory(const TIamHost& params): Params_(params) {} - - TCredentialsProviderPtr CreateProvider() const final { - return std::make_shared(Params_); - } - -private: - TIamHost Params_; -}; - -/// Acquire an IAM token using a local metadata service on a virtual machine. -TCredentialsProviderFactoryPtr CreateIamCredentialsProviderFactory(const TIamHost& params ) { - return std::make_shared(params); -} - -TCredentialsProviderFactoryPtr CreateIamJwtFileCredentialsProviderFactory(const TIamJwtFilename& params) { - TIamJwtParams jwtParams = { params, ReadJwtKeyFile(params.JwtFilename) }; - return std::make_shared>(std::move(jwtParams)); -} - -TCredentialsProviderFactoryPtr CreateIamJwtParamsCredentialsProviderFactory(const TIamJwtContent& params) { - TIamJwtParams jwtParams = { params, ParseJwtParams(params.JwtContent) }; - return std::make_shared>(std::move(jwtParams)); -} - -TCredentialsProviderFactoryPtr CreateIamOAuthCredentialsProviderFactory(const TIamOAuth& params) { - return std::make_shared>(params); - -} - -} diff --git a/include/ydb-cpp-sdk/client/iam/common/iam.h b/src/client/iam/common/iam.h similarity index 78% rename from include/ydb-cpp-sdk/client/iam/common/iam.h rename to src/client/iam/common/iam.h index ecc7e6462b..91ec93674e 100644 --- a/include/ydb-cpp-sdk/client/iam/common/iam.h +++ b/src/client/iam/common/iam.h @@ -1,69 +1,16 @@ #pragma once -#include +#include -#include -#include +#include -#include -#include +#include -#include #include - -#include +#include namespace NYdb { -namespace NIam { -constexpr std::string_view DEFAULT_ENDPOINT = "iam.api.cloud.yandex.net"; -constexpr bool DEFAULT_ENABLE_SSL = true; - -constexpr std::string_view DEFAULT_HOST = "169.254.169.254"; -constexpr uint32_t DEFAULT_PORT = 80; - -constexpr TDuration DEFAULT_REFRESH_PERIOD = TDuration::Hours(1); -constexpr TDuration DEFAULT_REQUEST_TIMEOUT = TDuration::Seconds(10); -} - -struct TIamHost { - std::string Host = std::string(NIam::DEFAULT_HOST); - uint32_t Port = NIam::DEFAULT_PORT; - TDuration RefreshPeriod = NIam::DEFAULT_REFRESH_PERIOD; -}; - -struct TIamEndpoint { - std::string Endpoint = std::string(NIam::DEFAULT_ENDPOINT); - TDuration RefreshPeriod = NIam::DEFAULT_REFRESH_PERIOD; - TDuration RequestTimeout = NIam::DEFAULT_REQUEST_TIMEOUT; - bool EnableSsl = NIam::DEFAULT_ENABLE_SSL; -}; - -struct TIamJwtFilename : TIamEndpoint { std::string JwtFilename; }; - -struct TIamJwtContent : TIamEndpoint { std::string JwtContent; }; - -struct TIamJwtParams : TIamEndpoint { TJwtParams JwtParams; }; - -inline TJwtParams ReadJwtKeyFile(const std::string& filename) { - std::ifstream input(filename, std::ios::in); - return ParseJwtParams({std::istreambuf_iterator(input), std::istreambuf_iterator()}); -} - -struct TIamOAuth : TIamEndpoint { std::string OAuthToken; }; - -/// Acquire an IAM token using a local metadata service on a virtual machine. -TCredentialsProviderFactoryPtr CreateIamCredentialsProviderFactory(const TIamHost& params = {}); - -/// Acquire an IAM token using a JSON Web Token (JWT) file name. -TCredentialsProviderFactoryPtr CreateIamJwtFileCredentialsProviderFactory(const TIamJwtFilename& params); - -/// Acquire an IAM token using JSON Web Token (JWT) contents. -TCredentialsProviderFactoryPtr CreateIamJwtParamsCredentialsProviderFactory(const TIamJwtContent& param); - -// Acquire an IAM token using a user OAuth token. -TCredentialsProviderFactoryPtr CreateIamOAuthCredentialsProviderFactory(const TIamOAuth& params); - constexpr TDuration BACKOFF_START = TDuration::MilliSeconds(50); constexpr TDuration BACKOFF_MAX = TDuration::Seconds(10); diff --git a/src/client/iam/iam.cpp b/src/client/iam/iam.cpp index 927add7057..032de620a6 100644 --- a/src/client/iam/iam.cpp +++ b/src/client/iam/iam.cpp @@ -1,12 +1,95 @@ -#include +#include + +#include "common/iam.h" #include #include +#include +#include + using namespace yandex::cloud::iam::v1; namespace NYdb { +class TIAMCredentialsProvider : public ICredentialsProvider { +public: + TIAMCredentialsProvider(const TIamHost& params) + : HttpClient_(TSimpleHttpClient(TString(params.Host), params.Port)) + , Request_("/computeMetadata/v1/instance/service-accounts/default/token") + , NextTicketUpdate_(TInstant::Zero()) + , RefreshPeriod_(params.RefreshPeriod) + { + GetTicket(); + } + + std::string GetAuthInfo() const override { + if (TInstant::Now() >= NextTicketUpdate_) { + GetTicket(); + } + return Ticket_; + } + + bool IsValid() const override { + return true; + } + +private: + TSimpleHttpClient HttpClient_; + std::string Request_; + mutable std::string Ticket_; + mutable TInstant NextTicketUpdate_; + TDuration RefreshPeriod_; + + void GetTicket() const { + try { + TStringStream out; + TSimpleHttpClient::THeaders headers; + headers["Metadata-Flavor"] = "Google"; + HttpClient_.DoGet(Request_, &out, headers); + NJson::TJsonValue resp; + NJson::ReadJsonTree(&out, &resp, true); + + auto respMap = resp.GetMap(); + + if (auto it = respMap.find("access_token"); it == respMap.end()) + ythrow yexception() << "Result doesn't contain access_token"; + else if (std::string ticket = it->second.GetStringSafe(); ticket.empty()) + ythrow yexception() << "Got empty ticket"; + else + Ticket_ = std::move(ticket); + + if (auto it = respMap.find("expires_in"); it == respMap.end()) + ythrow yexception() << "Result doesn't contain expires_in"; + else { + const TDuration expiresIn = TDuration::Seconds(it->second.GetUInteger()) / 2; + + const auto interval = std::max(std::min(expiresIn, RefreshPeriod_), TDuration::MilliSeconds(100)); + + NextTicketUpdate_ = TInstant::Now() + interval; + } + } catch (...) { + } + } +}; + +class TIamCredentialsProviderFactory : public ICredentialsProviderFactory { +public: + TIamCredentialsProviderFactory(const TIamHost& params): Params_(params) {} + + TCredentialsProviderPtr CreateProvider() const final { + return std::make_shared(Params_); + } + +private: + TIamHost Params_; +}; + +/// Acquire an IAM token using a local metadata service on a virtual machine. +TCredentialsProviderFactoryPtr CreateIamCredentialsProviderFactory(const TIamHost& params ) { + return std::make_shared(params); +} + TCredentialsProviderFactoryPtr CreateIamJwtFileCredentialsProviderFactory(const TIamJwtFilename& params) { TIamJwtParams jwtParams = { params, ReadJwtKeyFile(params.JwtFilename) }; return std::make_shared -#include +#include #include #include diff --git a/src/client/impl/ydb_internal/common/types.h b/src/client/impl/ydb_internal/common/types.h index 8d7dea5e7f..4c18d46221 100644 --- a/src/client/impl/ydb_internal/common/types.h +++ b/src/client/impl/ydb_internal/common/types.h @@ -7,7 +7,7 @@ #include -#include +#include namespace NYdb { diff --git a/src/client/impl/ydb_internal/db_driver_state/authenticator.h b/src/client/impl/ydb_internal/db_driver_state/authenticator.h index 32a6032883..9254093930 100644 --- a/src/client/impl/ydb_internal/db_driver_state/authenticator.h +++ b/src/client/impl/ydb_internal/db_driver_state/authenticator.h @@ -4,7 +4,7 @@ #include -#include +#include namespace NYdb { diff --git a/src/client/impl/ydb_internal/grpc_connections/actions.h b/src/client/impl/ydb_internal/grpc_connections/actions.h index 948c4bac2f..20150d7c25 100644 --- a/src/client/impl/ydb_internal/grpc_connections/actions.h +++ b/src/client/impl/ydb_internal/grpc_connections/actions.h @@ -7,7 +7,7 @@ #include #include -#include +#include #include diff --git a/src/client/impl/ydb_internal/plain_status/status.h b/src/client/impl/ydb_internal/plain_status/status.h index 768231d012..d0109d38e6 100644 --- a/src/client/impl/ydb_internal/plain_status/status.h +++ b/src/client/impl/ydb_internal/plain_status/status.h @@ -4,7 +4,7 @@ #include -#include +#include #include #include diff --git a/src/client/impl/ydb_stats/stats.h b/src/client/impl/ydb_stats/stats.h index 6a14b25bf0..a4c7a610cf 100644 --- a/src/client/impl/ydb_stats/stats.h +++ b/src/client/impl/ydb_stats/stats.h @@ -2,7 +2,7 @@ #include -#include +#include #include #include diff --git a/src/library/grpc/client/grpc_client_low.cpp b/src/library/grpc/client/grpc_client_low.cpp index ef39965dd2..452bd0b7df 100644 --- a/src/library/grpc/client/grpc_client_low.cpp +++ b/src/library/grpc/client/grpc_client_low.cpp @@ -1,4 +1,5 @@ -#include +#include "grpc_client_low.h" + #include #include diff --git a/include/ydb-cpp-sdk/library/grpc/client/grpc_client_low.h b/src/library/grpc/client/grpc_client_low.h similarity index 100% rename from include/ydb-cpp-sdk/library/grpc/client/grpc_client_low.h rename to src/library/grpc/client/grpc_client_low.h diff --git a/include/ydb-cpp-sdk/library/grpc/client/grpc_common.h b/src/library/grpc/client/grpc_common.h similarity index 98% rename from include/ydb-cpp-sdk/library/grpc/client/grpc_common.h rename to src/library/grpc/client/grpc_common.h index 58adfeda3e..7ae782ebc8 100644 --- a/include/ydb-cpp-sdk/library/grpc/client/grpc_common.h +++ b/src/library/grpc/client/grpc_common.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include diff --git a/include/ydb-cpp-sdk/library/grpc/common/constants.h b/src/library/grpc/common/constants.h similarity index 100% rename from include/ydb-cpp-sdk/library/grpc/common/constants.h rename to src/library/grpc/common/constants.h diff --git a/tests/unit/library/grpc_client/grpc_client_low_ut.cpp b/tests/unit/library/grpc_client/grpc_client_low_ut.cpp index 4abbafee7c..35a89328cb 100644 --- a/tests/unit/library/grpc_client/grpc_client_low_ut.cpp +++ b/tests/unit/library/grpc_client/grpc_client_low_ut.cpp @@ -1,4 +1,4 @@ -#include +#include #include