diff --git a/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/keyvault_secrets.hpp b/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/keyvault_secrets.hpp index 6df9ba8a8..0e63d7e15 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/keyvault_secrets.hpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/inc/azure/keyvault/keyvault_secrets.hpp @@ -9,4 +9,7 @@ #pragma once #include "azure/keyvault/secrets/dll_import_export.hpp" +#include "azure/keyvault/secrets/keyvault_deleted_secret.hpp" +#include "azure/keyvault/secrets/keyvault_secret.hpp" +#include "azure/keyvault/secrets/keyvault_secret_properties.hpp" #include "azure/keyvault/secrets/secret_client.hpp" 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 2787c983f..6197d5eaa 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 @@ -82,12 +82,24 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { struct GetSecretOptions final { /** - * @brief Specify the key version to get. + * @brief Specify the secret version to get. * */ std::string Version; }; + /** + * @brief Optional parameters for SecretClient::UpdateSecretParameters + * + */ + struct UpdateSecretPropertiesOptions final + { + /** + * @brief Specify the secret version to update. + * + */ + std::string Version; + }; /** * @brief The SecretClient provides synchronous methods to manage a secret in the Azure Key * Vault. The client supports creating, retrieving, updating, deleting, purging, backing up, @@ -183,6 +195,46 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { std::string const& name, KeyVaultSecret const& secret, Azure::Core::Context const& context = Azure::Core::Context()) const; + + /** + * @brief Updates the attributes associated with a specified secret in a given key vault. + * The UPDATE operation changes specified attributes of an existing stored secret. + * Attributes that are not specified in the request are left unchanged. + * The value of a secret itself cannot be changed. + * This operation requires the secrets/set permission. + * + * @param name The name of the secret. + * @param options The optional parameters for this request. + * @param properties The properties to update + * @param context The context for the operation can be used for request cancellation. + * + * @return The Secret wrapped in the Response. + */ + Azure::Response UpdateSecretProperties( + std::string const& name, + UpdateSecretPropertiesOptions const& options, + KeyvaultSecretProperties const& properties, + Azure::Core::Context const& context = Azure::Core::Context()) const; + + /** + * @brief Update the attributes associated with a specified secret in a given key vault. + * The UPDATE operation changes specified attributes of an existing stored secret. + * Attributes that are not specified in the request are left unchanged. + * The value of a secret itself cannot be changed. + * This operation requires the secrets/set permission. + * + * @param name The name of the secret. + * @param version The version of the secret for this request. + * @param properties The properties to update + * @param context The context for the operation can be used for request cancellation. + * + * @return The Secret wrapped in the Response. + */ + Azure::Response UpdateSecretProperties( + std::string const& name, + std::string const& version, + KeyvaultSecretProperties const& properties, + Azure::Core::Context const& context = Azure::Core::Context()) const; }; }}}} // namespace Azure::Security::KeyVault::Secrets diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_serializers.hpp b/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_serializers.hpp index d6aca6e9b..8aba3bde9 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_serializers.hpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/private/secret_serializers.hpp @@ -97,4 +97,10 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { KeyVaultDeletedSecret& secret, Azure::Core::Http::RawResponse const& rawResponse); }; + + struct KeyVaultSecretPropertiesSerializer final + { + static std::string KeyVaultSecretPropertiesSerialize( + KeyvaultSecretProperties const& properties); + }; }}}}} // namespace Azure::Security::KeyVault::Secrets::_detail 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 b07f3b324..43098c968 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/src/secret_client.cpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/secret_client.cpp @@ -102,4 +102,35 @@ Azure::Response SecretClient::SetSecret( {_detail::SecretPath, name}); } +Azure::Response SecretClient::UpdateSecretProperties( + std::string const& name, + UpdateSecretPropertiesOptions const& options, + KeyvaultSecretProperties const& properties, + Azure::Core::Context const& context) const +{ + return m_protocolClient->SendRequest( + context, + Azure::Core::Http::HttpMethod::Patch, + [&properties]() { + return _detail::KeyVaultSecretPropertiesSerializer::KeyVaultSecretPropertiesSerialize( + properties); + }, + [&name](Azure::Core::Http::RawResponse const& rawResponse) { + return _detail::KeyVaultSecretSerializer::KeyVaultSecretDeserialize(name, rawResponse); + }, + {_detail::SecretPath, name, options.Version}); +} + +Azure::Response SecretClient::UpdateSecretProperties( + std::string const& name, + std::string const& version, + KeyvaultSecretProperties const& properties, + Azure::Core::Context const& context) const +{ + UpdateSecretPropertiesOptions options; + options.Version = version; + + return UpdateSecretProperties(name, options, properties, context); +} + const ServiceVersion ServiceVersion::V7_2("7.2"); diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/secret_serializers.cpp b/sdk/keyvault/azure-security-keyvault-secrets/src/secret_serializers.cpp index 503391412..5652246b5 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/src/secret_serializers.cpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/src/secret_serializers.cpp @@ -156,7 +156,7 @@ void KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize( // serializes a set secret parameters object std::string KeyVaultSecretSerializer::KeyVaultSecretSerialize(KeyVaultSecret const& parameters) { - Azure::Core::Json::_internal::json payload; + json payload; using namespace Azure::Security::KeyVault::Secrets::_detail; // value is required @@ -166,7 +166,7 @@ std::string KeyVaultSecretSerializer::KeyVaultSecretSerialize(KeyVaultSecret con JsonOptional::SetFromNullable( parameters.Properties.ContentType, payload, ContentTypePropertyName); - Azure::Core::Json::_internal::json attributes; + json attributes; JsonOptional::SetFromNullable( parameters.Properties.CreatedOn, @@ -195,7 +195,42 @@ std::string KeyVaultSecretSerializer::KeyVaultSecretSerialize(KeyVaultSecret con PosixTimeConverter::DateTimeToPosixTime); // optional tags - attributes[TagsPropertyName] = Azure::Core::Json::_internal::json(parameters.Properties.Tags); + attributes[TagsPropertyName] = json(parameters.Properties.Tags); + + payload[AttributesPropertyName] = attributes; + + return payload.dump(); +} + +std::string KeyVaultSecretPropertiesSerializer::KeyVaultSecretPropertiesSerialize( + KeyvaultSecretProperties const& properties) +{ + json payload; + + // content type + JsonOptional::SetFromNullable(properties.ContentType, payload, _detail::ContentTypePropertyName); + + // optional tags + payload[TagsPropertyName] = json(properties.Tags); + + // attributes + json attributes; + + JsonOptional::SetFromNullable( + properties.RecoverableDays, attributes, _detail::RecoverableDaysPropertyName); + JsonOptional::SetFromNullable( + properties.RecoveryLevel, attributes, _detail::RecoveryLevelPropertyName); + JsonOptional::SetFromNullable(properties.Enabled, attributes, _detail::EnabledPropertyName); + JsonOptional::SetFromNullable( + properties.NotBefore, + attributes, + _detail::NbfPropertyName, + PosixTimeConverter::DateTimeToPosixTime); + JsonOptional::SetFromNullable( + properties.ExpiresOn, + attributes, + _detail::ExpPropertyName, + PosixTimeConverter::DateTimeToPosixTime); payload[AttributesPropertyName] = attributes; diff --git a/sdk/keyvault/azure-security-keyvault-secrets/test/sample/test_app.cpp b/sdk/keyvault/azure-security-keyvault-secrets/test/sample/test_app.cpp index ec4084615..43a2f841f 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/test/sample/test_app.cpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/test/sample/test_app.cpp @@ -5,7 +5,6 @@ #endif #include - #include using namespace Azure::Security::KeyVault::Secrets; @@ -19,10 +18,13 @@ int main() = std::make_shared(tenantId, clientId, clientSecret); SecretClient secretClient(std::getenv("AZURE_KEYVAULT_URL"), credential); + // just a response, with a secret + auto response = secretClient.GetSecret("testSecret"); + response.Value.Properties.ContentType = "weqeq"; + GetSecretOptions options; - auto response = secretClient.SetSecret("someSecret3", "someData"); - - auto response2 = secretClient.GetSecret("someSecret3"); + response = secretClient.UpdateSecretProperties( + response.Value.Name, response.Value.Properties.Version, response.Value.Properties); // just a response, with a secret auto response3 = secretClient.GetDeletedSecret("someSecret"); diff --git a/sdk/keyvault/azure-security-keyvault-secrets/test/ut/CMakeLists.txt b/sdk/keyvault/azure-security-keyvault-secrets/test/ut/CMakeLists.txt index 7ec780a1a..8f5120786 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/test/ut/CMakeLists.txt +++ b/sdk/keyvault/azure-security-keyvault-secrets/test/ut/CMakeLists.txt @@ -16,7 +16,8 @@ add_executable ( secret_get_client_deserialize_test.hpp secret_get_client_deserialize_test.cpp secret_set_parameters_serializer_test.cpp - ) + secret_update_properties_test.cpp + ) if (MSVC) target_compile_options(azure-security-keyvault-secrets-test PUBLIC /wd6326 /wd26495 /wd26812) diff --git a/sdk/keyvault/azure-security-keyvault-secrets/test/ut/secret_get_client_deserialize_test.hpp b/sdk/keyvault/azure-security-keyvault-secrets/test/ut/secret_get_client_deserialize_test.hpp index a887b351a..5e11773d2 100644 --- a/sdk/keyvault/azure-security-keyvault-secrets/test/ut/secret_get_client_deserialize_test.hpp +++ b/sdk/keyvault/azure-security-keyvault-secrets/test/ut/secret_get_client_deserialize_test.hpp @@ -43,7 +43,6 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { } static Azure::Core::Http::RawResponse GetFullResponse() - { auto response = Azure::Core::Http::RawResponse(1, 1, Azure::Core::Http::HttpStatusCode::Ok, "OK"); diff --git a/sdk/keyvault/azure-security-keyvault-secrets/test/ut/secret_update_properties_test.cpp b/sdk/keyvault/azure-security-keyvault-secrets/test/ut/secret_update_properties_test.cpp new file mode 100644 index 000000000..b1ea955d7 --- /dev/null +++ b/sdk/keyvault/azure-security-keyvault-secrets/test/ut/secret_update_properties_test.cpp @@ -0,0 +1,85 @@ +#include "../src/private/secret_serializers.hpp" +#include "azure/core/internal/json/json.hpp" +#include "azure/core/internal/json/json_optional.hpp" +#include "azure/core/internal/json/json_serializable.hpp" +#include "azure/keyvault/secrets/secret_client.hpp" +#include "private/secret_constants.hpp" +#include "secret_get_client_deserialize_test.hpp" + +using namespace Azure::Security::KeyVault::Secrets; +using namespace Azure::Security::KeyVault::Secrets::_detail; +using namespace Azure::Core::Json::_internal; + +TEST(KeyVaultSecretPropertiesSerializer, Serialize1) +{ + KeyvaultSecretProperties properties; + + properties.ContentType = "contentType"; + properties.Enabled = true; + properties.RecoverableDays = 5; + + auto serialized + = _detail::KeyVaultSecretPropertiesSerializer::KeyVaultSecretPropertiesSerialize(properties); + + auto jsonParser = json::parse(serialized); + + EXPECT_EQ(properties.ContentType.Value(), jsonParser[_detail::ContentTypePropertyName]); + EXPECT_EQ( + properties.Enabled.Value(), + jsonParser[_detail::AttributesPropertyName][_detail::EnabledPropertyName]); + EXPECT_EQ( + properties.RecoverableDays.Value(), + jsonParser[_detail::AttributesPropertyName][_detail::RecoverableDaysPropertyName]); +} + +TEST(KeyVaultSecretPropertiesSerializer, Serialize2) +{ + KeyvaultSecretProperties properties; + + properties.ContentType = "contentType"; + properties.Enabled = true; + properties.RecoverableDays = 5; + properties.Tags.emplace("a", "b"); + + auto serialized + = _detail::KeyVaultSecretPropertiesSerializer::KeyVaultSecretPropertiesSerialize(properties); + + auto jsonParser = json::parse(serialized); + + EXPECT_EQ(properties.ContentType.Value(), jsonParser[_detail::ContentTypePropertyName]); + EXPECT_EQ( + properties.Enabled.Value(), + jsonParser[_detail::AttributesPropertyName][_detail::EnabledPropertyName]); + EXPECT_EQ( + properties.RecoverableDays.Value(), + jsonParser[_detail::AttributesPropertyName][_detail::RecoverableDaysPropertyName]); + EXPECT_EQ(properties.Tags["a"], jsonParser[_detail::TagsPropertyName]["a"]); +} + +TEST(KeyVaultSecretPropertiesSerializer, Serialize3) +{ + KeyvaultSecretProperties properties; + + properties.ContentType = "contentType"; + properties.Enabled = true; + properties.RecoverableDays = 5; + properties.Tags.emplace("a", "b"); + properties.Tags.emplace("c", "d"); + + auto serialized + = _detail::KeyVaultSecretPropertiesSerializer::KeyVaultSecretPropertiesSerialize(properties); + + auto jsonParser = json::parse(serialized); + + EXPECT_EQ(properties.ContentType.Value(), jsonParser[_detail::ContentTypePropertyName]); + EXPECT_EQ( + properties.Enabled.Value(), + jsonParser[_detail::AttributesPropertyName][_detail::EnabledPropertyName]); + EXPECT_EQ( + properties.RecoverableDays.Value(), + jsonParser[_detail::AttributesPropertyName][_detail::RecoverableDaysPropertyName]); + for (auto kvp : properties.Tags) + { + EXPECT_EQ(properties.Tags[kvp.first], jsonParser[_detail::TagsPropertyName][kvp.first]); + } +}