diff --git a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt index 44d13a436..94b1ec31c 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt +++ b/sdk/keyvault/azure-security-keyvault-secrets/CMakeLists.txt @@ -65,12 +65,14 @@ set( src/private/keyvault_protocol.hpp src/private/secret_constants.hpp src/private/secret_serializers.hpp + src/private/keyvault_secrets_common_request.hpp src/keyvault_protocol.cpp src/secret_client.cpp src/secret_serializers.cpp src/keyvault_operations.cpp src/keyvault_secret_paged_response.cpp src/keyvault_secret_properties.cpp + src/keyvault_secrets_common_request.cpp ) add_library(azure-security-keyvault-secrets ${AZURE_SECURITY_KEYVAULT_SECRETS_HEADER} ${AZURE_SECURITY_KEYVAULT_SECRETS_SOURCE}) diff --git a/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/secrets/secret_client.hpp b/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/secrets/secret_client.hpp index b2c3f69c4..473a060d5 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/secrets/secret_client.hpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/secrets/secret_client.hpp @@ -48,7 +48,9 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { private: // Using a shared pipeline for a client to share it with LRO (like delete key) - std::shared_ptr m_protocolClient; + Azure::Core::Url m_vaultUrl; + std::string m_apiVersion; + std::shared_ptr m_pipeline; public: /** @@ -69,7 +71,9 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { * @param keyClient An existing key vault key client. */ explicit SecretClient(SecretClient const& keyClient) - : m_protocolClient(keyClient.m_protocolClient) + : m_vaultUrl(keyClient.m_vaultUrl), m_apiVersion(keyClient.m_apiVersion), + m_pipeline(keyClient.m_pipeline) + { } @@ -277,5 +281,17 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { * @return The key secret's primary URL endpoint. */ std::string GetUrl() const; + + private: + Azure::Core::Http::Request CreateRequest( + Azure::Core::Http::HttpMethod method, + std::vector const& path = {}, + Azure::Core::IO::BodyStream* content = nullptr) const; + Azure::Core::Http::Request ContinuationTokenRequest( + std::vector const& path, + const Azure::Nullable& NextPageToken) const; + std::unique_ptr SendRequest( + Azure::Core::Http::Request& request, + Azure::Core::Context const& context) const; }; }}}} // namespace Azure::Security::KeyVault::Secrets diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/keyvault_secrets_common_request.cpp b/sdk/keyvault/azure-security-keyvault-secrets/src/keyvault_secrets_common_request.cpp new file mode 100644 index 000000000..6931cf685 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/keyvault_secrets_common_request.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +#include "private/keyvault_secrets_common_request.hpp" + +#include +#include +#include + +using namespace Azure::Security::KeyVault::Secrets; +using namespace Azure::Core::Http::_internal; + +std::unique_ptr _detail::KeyVaultSecretsCommonRequest::SendRequest( + Azure::Core::Http::_internal::HttpPipeline const& pipeline, + Azure::Core::Http::Request& request, + Azure::Core::Context const& context) +{ + auto response = pipeline.Send(request, context); + auto responseCode = response->GetStatusCode(); + + switch (responseCode) + { + + // 200, 201, 202, 204 are accepted responses + case Azure::Core::Http::HttpStatusCode::Ok: + case Azure::Core::Http::HttpStatusCode::Created: + case Azure::Core::Http::HttpStatusCode::Accepted: + case Azure::Core::Http::HttpStatusCode::NoContent: + break; + default: + throw Azure::Core::RequestFailedException(response); + } + return response; +} + +Azure::Core::Http::Request _detail::KeyVaultSecretsCommonRequest::CreateRequest( + Azure::Core::Url url, + std::string const& apiVersion, + Azure::Core::Http::HttpMethod method, + std::vector const& path, + Azure::Core::IO::BodyStream* content) +{ + using namespace Azure::Core::Http; + Request request = content == nullptr ? Request(method, url) : Request(method, url, content); + + request.SetHeader(ContentHeaderName, ApplicationJsonValue); + request.GetUrl().AppendQueryParameter(ApiVersionQueryParamName, apiVersion); + + for (std::string const& p : path) + { + if (!p.empty()) + { + request.GetUrl().AppendPath(p); + } + } + return request; +} diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/private/keyvault_secrets_common_request.hpp b/sdk/keyvault/azure-security-keyvault-secrets/src/private/keyvault_secrets_common_request.hpp new file mode 100644 index 000000000..a7d745404 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/private/keyvault_secrets_common_request.hpp @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// SPDX-License-Identifier: MIT + +/** + * @brief Provides a wrapper class for the Azure Core Pipeline for Secrets service. + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { namespace _detail { + + constexpr static const char ContentHeaderName[] = "content-type"; + constexpr static const char ApplicationJsonValue[] = "application/json"; + constexpr static const char ApiVersionQueryParamName[] = "api-version"; + + struct KeyVaultSecretsCommonRequest final + { + static Azure::Core::Http::Request CreateRequest( + Azure::Core::Url url, + std::string const& apiVersion, + Azure::Core::Http::HttpMethod method, + std::vector const& path, + Azure::Core::IO::BodyStream* content); + + static std::unique_ptr SendRequest( + Azure::Core::Http::_internal::HttpPipeline const& pipeline, + Azure::Core::Http::Request& request, + Azure::Core::Context const& context); + }; + +}}}}} // namespace Azure::Security::KeyVault::Secrets::_detail diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_constants.hpp b/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_constants.hpp index b6905beb0..c68e0d2b1 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_constants.hpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_constants.hpp @@ -13,6 +13,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { namespace _detail { + constexpr static const char KeyVaultServicePackageName[] = "keyvault-secrets"; /***************** KeyVault Secret *****************/ constexpr static const char SecretPath[] = "secrets"; static constexpr char const DeletedSecretPath[] = "deletedsecrets"; diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/secret_client.cpp b/sdk/keyvault/azure-security-keyvault-secrets/src/secret_client.cpp index fea853113..7ca5dae70 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/src/secret_client.cpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/secret_client.cpp @@ -9,61 +9,61 @@ #include "azure/keyvault/secrets/secret_client.hpp" #include "azure/keyvault/secrets/keyvault_operations.hpp" #include "private/keyvault_protocol.hpp" +#include "private/keyvault_secrets_common_request.hpp" #include "private/package_version.hpp" #include "private/secret_constants.hpp" #include "private/secret_serializers.hpp" -#include - #include #include #include +#include #include #include - +using namespace Azure::Core::Http; using namespace Azure::Security::KeyVault::Secrets; using namespace Azure::Core::Http::Policies; using namespace Azure::Core::Http::Policies::_internal; using namespace Azure::Security::KeyVault::Secrets::_detail; -namespace { -constexpr static const char TelemetryName[] = "keyvault-secrets"; +const ServiceVersion ServiceVersion::V7_2("7.2"); -struct RequestWithContinuationToken final +std::unique_ptr SecretClient::SendRequest( + Azure::Core::Http::Request& request, + Azure::Core::Context const& context) const { - std::vector Path; - std::unique_ptr> Query; -}; + return KeyVaultSecretsCommonRequest::SendRequest(*m_pipeline, request, context); +} -static inline RequestWithContinuationToken BuildRequestFromContinuationToken( - const Azure::Nullable& NextPageToken, - std::vector defaultPath) +Request SecretClient::CreateRequest( + HttpMethod method, + std::vector const& path, + Azure::Core::IO::BodyStream* content) const +{ + return KeyVaultSecretsCommonRequest::CreateRequest( + m_vaultUrl, m_apiVersion, method, path, content); +} + +Request SecretClient::ContinuationTokenRequest( + std::vector const& path, + const Azure::Nullable& NextPageToken) const { - RequestWithContinuationToken request; - request.Path = std::move(defaultPath); - request.Query = std::make_unique>(); if (NextPageToken) { // Using a continuation token requires to send the request to the continuation token URL instead // of the default URL which is used only for the first page. Azure::Core::Url nextPageUrl(NextPageToken.Value()); - auto queryParameters = nextPageUrl.GetQueryParameters(); - request.Query->insert(queryParameters.begin(), queryParameters.end()); - request.Path.clear(); - request.Path.emplace_back(nextPageUrl.GetPath()); + return Request(HttpMethod::Get, nextPageUrl); } - return request; + return CreateRequest(HttpMethod::Get, path); } -} // namespace - -const ServiceVersion ServiceVersion::V7_2("7.2"); - SecretClient::SecretClient( std::string const& vaultUrl, std::shared_ptr credential, SecretClientOptions options) + : m_vaultUrl(vaultUrl), m_apiVersion(options.Version.ToString()) { auto apiVersion = options.Version.ToString(); Azure::Core::Url url(vaultUrl); @@ -77,11 +77,14 @@ SecretClient::SecretClient( std::make_unique(credential, tokenContext)); } - m_protocolClient = std::make_shared( - std::move(url), - apiVersion, - Azure::Core::Http::_internal::HttpPipeline( - options, TelemetryName, PackageVersion::ToString(), std::move(perRetrypolicies), {})); + std::vector> perCallpolicies; + + m_pipeline = std::make_shared( + options, + KeyVaultServicePackageName, + PackageVersion::ToString(), + std::move(perRetrypolicies), + std::move(perCallpolicies)); } Azure::Response SecretClient::GetSecret( @@ -89,26 +92,24 @@ Azure::Response SecretClient::GetSecret( GetSecretOptions const& options, Azure::Core::Context const& context) const { - return m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Get, - [&name](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::SecretSerializer::Deserialize(name, rawResponse); - }, - {_detail::SecretPath, name, options.Version}); + auto request = CreateRequest(HttpMethod::Get, {_detail::SecretPath, name, options.Version}); + + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::SecretSerializer::Deserialize(name, *rawResponse); + return Azure::Response(std::move(value), std::move(rawResponse)); } Azure::Response SecretClient::GetDeletedSecret( std::string const& name, Azure::Core::Context const& context) const { - return m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Get, - [&name](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::DeletedSecretSerializer::Deserialize(name, rawResponse); - }, - {_detail::DeletedSecretPath, name}); + auto request = CreateRequest(HttpMethod::Get, {_detail::DeletedSecretPath, name}); + + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::DeletedSecretSerializer::Deserialize(name, *rawResponse); + return Azure::Response(std::move(value), std::move(rawResponse)); } Azure::Response SecretClient::SetSecret( @@ -125,118 +126,112 @@ Azure::Response SecretClient::SetSecret( KeyVaultSecret const& secret, Azure::Core::Context const& context) const { - return m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Put, - [&secret]() { return _detail::SecretSerializer::Serialize(secret); }, - [&name](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::SecretSerializer::Deserialize(name, rawResponse); - }, - {_detail::SecretPath, name}); + auto payload = _detail::SecretSerializer::Serialize(secret); + Azure::Core::IO::MemoryBodyStream payloadStream( + reinterpret_cast(payload.data()), payload.size()); + + auto request = CreateRequest(HttpMethod::Put, {_detail::SecretPath, name}, &payloadStream); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::SecretSerializer::Deserialize(name, *rawResponse); + return Azure::Response(std::move(value), std::move(rawResponse)); } Azure::Response SecretClient::UpdateSecretProperties( SecretProperties const& properties, Azure::Core::Context const& context) const { - return m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Patch, - [&properties]() { return _detail::SecretPropertiesSerializer::Serialize(properties); }, - [&properties](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::SecretSerializer::Deserialize(properties.Name, rawResponse); - }, - {_detail::SecretPath, properties.Name, properties.Version}); + auto payload = _detail::SecretPropertiesSerializer::Serialize(properties); + Azure::Core::IO::MemoryBodyStream payloadStream( + reinterpret_cast(payload.data()), payload.size()); + + auto request = CreateRequest( + HttpMethod::Patch, + {_detail::SecretPath, properties.Name, properties.Version}, + &payloadStream); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::SecretSerializer::Deserialize(properties.Name, *rawResponse); + return Azure::Response(std::move(value), std::move(rawResponse)); } Azure::Response SecretClient::BackupSecret( std::string const& name, Azure::Core::Context const& context) const { - return m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Post, - [](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::BackupSecretSerializer::Deserialize(rawResponse); - }, - {_detail::SecretPath, name, _detail::BackupSecretPath}); + auto request + = CreateRequest(HttpMethod::Post, {_detail::SecretPath, name, _detail::BackupSecretPath}); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::BackupSecretSerializer::Deserialize(*rawResponse); + return Azure::Response(std::move(value), std::move(rawResponse)); } Azure::Response SecretClient::RestoreSecretBackup( BackupSecretResult const& backup, Azure::Core::Context const& context) const { - return m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Post, - [&backup]() { return _detail::RestoreSecretSerializer::Serialize(backup.Secret); }, - [](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::SecretSerializer::Deserialize(rawResponse); - }, - {_detail::SecretPath, _detail::RestoreSecretPath}); + auto payload = _detail::RestoreSecretSerializer::Serialize(backup.Secret); + Azure::Core::IO::MemoryBodyStream payloadStream( + reinterpret_cast(payload.data()), payload.size()); + + auto request = CreateRequest( + HttpMethod::Post, {_detail::SecretPath, _detail::RestoreSecretPath}, &payloadStream); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::SecretSerializer::Deserialize(*rawResponse); + return Azure::Response(std::move(value), std::move(rawResponse)); } Azure::Response SecretClient::PurgeDeletedSecret( std::string const& name, Azure::Core::Context const& context) const { - return m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Delete, - [](Azure::Core::Http::RawResponse const&) { return PurgedSecret(); }, - {_detail::DeletedSecretPath, name}); + auto request = CreateRequest(HttpMethod::Delete, {_detail::DeletedSecretPath, name}); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + PurgedSecret value; + return Azure::Response(std::move(value), std::move(rawResponse)); } Azure::Security::KeyVault::Secrets::DeleteSecretOperation SecretClient::StartDeleteSecret( std::string const& name, Azure::Core::Context const& context) const { - return Azure::Security::KeyVault::Secrets::DeleteSecretOperation( - std::make_shared(*this), - m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Delete, - [&name](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::DeletedSecretSerializer::Deserialize(name, rawResponse); - }, - {_detail::SecretPath, name})); + auto request = CreateRequest(HttpMethod::Delete, {_detail::SecretPath, name}); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::DeletedSecretSerializer::Deserialize(name, *rawResponse); + auto responseT = Azure::Response(std::move(value), std::move(rawResponse)); + return DeleteSecretOperation(std::make_shared(*this), std::move(responseT)); } Azure::Security::KeyVault::Secrets::RecoverDeletedSecretOperation SecretClient:: StartRecoverDeletedSecret(std::string const& name, Azure::Core::Context const& context) const { - return Azure::Security::KeyVault::Secrets::RecoverDeletedSecretOperation( - std::make_shared(*this), - m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Post, - [&name](Azure::Core::Http::RawResponse const& rawResponse) { - auto parsedResponse = _detail::SecretSerializer::Deserialize(name, rawResponse); - return parsedResponse.Properties; - }, - {_detail::DeletedSecretPath, name, _detail::RecoverDeletedSecretPath})); + auto request = CreateRequest( + HttpMethod::Post, {_detail::DeletedSecretPath, name, _detail::RecoverDeletedSecretPath}); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto parsedResponse = _detail::SecretSerializer::Deserialize(name, *rawResponse); + + auto value = parsedResponse.Properties; + auto responseT = Azure::Response(std::move(value), std::move(rawResponse)); + return RecoverDeletedSecretOperation(std::make_shared(*this), std::move(responseT)); } SecretPropertiesPagedResponse SecretClient::GetPropertiesOfSecrets( GetPropertiesOfSecretsOptions const& options, Azure::Core::Context const& context) const { - auto const request - = BuildRequestFromContinuationToken(options.NextPageToken, {_detail::SecretPath}); - - auto response = m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Get, - [](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::SecretPropertiesPagedResultSerializer::Deserialize(rawResponse); - }, - request.Path, - request.Query); + // Request and settings + auto request = ContinuationTokenRequest({SecretPath}, options.NextPageToken); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::SecretPropertiesPagedResultSerializer::Deserialize(*rawResponse); return SecretPropertiesPagedResponse( - std::move(response.Value), - std::move(response.RawResponse), - std::make_unique(*this)); + std::move(value), std::move(rawResponse), std::make_unique(*this)); } SecretPropertiesPagedResponse SecretClient::GetPropertiesOfSecretsVersions( @@ -244,45 +239,29 @@ SecretPropertiesPagedResponse SecretClient::GetPropertiesOfSecretsVersions( GetPropertiesOfSecretVersionsOptions const& options, Azure::Core::Context const& context) const { - auto const request = BuildRequestFromContinuationToken( - options.NextPageToken, {_detail::SecretPath, name, _detail::VersionsName}); - - auto response = m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Get, - [](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::SecretPropertiesPagedResultSerializer::Deserialize(rawResponse); - }, - request.Path, - request.Query); + // Request and settings + auto request = ContinuationTokenRequest( + {_detail::SecretPath, name, _detail::VersionsName}, options.NextPageToken); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::SecretPropertiesPagedResultSerializer::Deserialize(*rawResponse); return SecretPropertiesPagedResponse( - std::move(response.Value), - std::move(response.RawResponse), - std::make_unique(*this), - name); + std::move(value), std::move(rawResponse), std::make_unique(*this), name); } DeletedSecretPagedResponse SecretClient::GetDeletedSecrets( GetDeletedSecretsOptions const& options, Azure::Core::Context const& context) const { - auto const request - = BuildRequestFromContinuationToken(options.NextPageToken, {_detail::DeletedSecretPath}); - - auto response = m_protocolClient->SendRequest( - context, - Azure::Core::Http::HttpMethod::Get, - [](Azure::Core::Http::RawResponse const& rawResponse) { - return _detail::DeletedSecretPagedResultSerializer::Deserialize(rawResponse); - }, - request.Path, - request.Query); + // Request and settings + auto request = ContinuationTokenRequest({_detail::DeletedSecretPath}, options.NextPageToken); + // Send and parse respone + auto rawResponse = SendRequest(request, context); + auto value = _detail::DeletedSecretPagedResultSerializer::Deserialize(*rawResponse); return DeletedSecretPagedResponse( - std::move(response.Value), - std::move(response.RawResponse), - std::make_unique(*this)); + std::move(value), std::move(rawResponse), std::make_unique(*this)); } -std::string SecretClient::GetUrl() const { return m_protocolClient->GetUrl().GetAbsoluteUrl(); } +std::string SecretClient::GetUrl() const { return m_vaultUrl.GetAbsoluteUrl(); }