parent
5210e8eb0d
commit
a5bc8fe0ef
@ -0,0 +1,74 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Define a convenience layer on top of Json for setting optional fields.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "azure/core/internal/json/json.hpp"
|
||||
#include "azure/core/nullable.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Core { namespace Json { namespace _internal {
|
||||
|
||||
/**
|
||||
* @brief Define a wrapper for working with Json containing optional fields.
|
||||
*
|
||||
*/
|
||||
struct JsonOptional
|
||||
{
|
||||
/**
|
||||
* @brief If the optional key \p key is present in the json node \p jsonKey set the value of \p
|
||||
* destination.
|
||||
*
|
||||
* @remark If the key is not in the json node, the \p destination is not modified.
|
||||
*
|
||||
* @param jsonKey The json node to review.
|
||||
* @param key The key name for the optional property.
|
||||
* @param destination The value to update if the key name property is in the json node.
|
||||
*/
|
||||
template <class T>
|
||||
static inline void SetIfExists(
|
||||
Azure::Nullable<T>& destination,
|
||||
Azure::Core::Json::_internal::json const& jsonKey,
|
||||
std::string const& key) noexcept
|
||||
{
|
||||
if (jsonKey.contains(key))
|
||||
{
|
||||
destination = jsonKey[key].get<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief If the optional key \p key is present in the json node \p jsonKey set the value of \p
|
||||
* destination.
|
||||
*
|
||||
* @remark If the key is not in the json node, the \p destination is not modified.
|
||||
*
|
||||
* @param jsonKey The json node to review.
|
||||
* @param key The key name for the optional property.
|
||||
* @param destination The value to update if the key name property is in the json node.
|
||||
* @param decorator A optional function to update the json value before updating the \p
|
||||
* destination.
|
||||
*/
|
||||
template <class T, class V>
|
||||
static inline void SetIfExists(
|
||||
Azure::Nullable<V>& destination,
|
||||
Azure::Core::Json::_internal::json const& jsonKey,
|
||||
std::string const& key,
|
||||
std::function<V(T value)> decorator) noexcept
|
||||
{
|
||||
if (jsonKey.contains(key))
|
||||
{
|
||||
destination = decorator(jsonKey[key].get<T>());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}}}} // namespace Azure::Core::Json::_internal
|
||||
@ -163,5 +163,20 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
|
||||
Azure::Security::KeyVault::Keys::DeleteKeyOperation StartDeleteKey(
|
||||
std::string const& name,
|
||||
Azure::Core::Context const& context = Azure::Core::Context()) const;
|
||||
|
||||
/**
|
||||
* @brief Gets the public part of a deleted key.
|
||||
*
|
||||
* @remark The Get Deleted Key operation is applicable for soft-delete enabled vaults. While the
|
||||
* operation can be invoked on any vault, it will return an error if invoked on a non
|
||||
* soft-delete enabled vault. This operation requires the keys/get permission.
|
||||
*
|
||||
* @param name The name of the key.
|
||||
* @param context A #Azure::Core::Context controlling the request lifetime.
|
||||
* @return Azure::Response<DeletedKey>
|
||||
*/
|
||||
Azure::Response<DeletedKey> GetDeletedKey(
|
||||
std::string const& name,
|
||||
Azure::Core::Context const& context = Azure::Core::Context()) const;
|
||||
};
|
||||
}}}} // namespace Azure::Security::KeyVault::Keys
|
||||
|
||||
@ -36,6 +36,10 @@ Azure::Security::KeyVault::Keys::DeleteKeyOperation::PollInternal(Azure::Core::C
|
||||
rawResponse = m_pipeline->GetResponse(
|
||||
context, Azure::Core::Http::HttpMethod::Get, {_detail::DeletedKeysPath, m_value.Name()});
|
||||
m_status = CheckCompleted(*rawResponse);
|
||||
if (m_status == Azure::Core::OperationStatus::Succeeded)
|
||||
{
|
||||
m_value = _detail::DeletedKeyDeserialize(m_value.Name(), *rawResponse);
|
||||
}
|
||||
}
|
||||
|
||||
// To ensure the success of calling Poll multiple times, even after operation is completed, a
|
||||
|
||||
@ -129,3 +129,16 @@ Azure::Security::KeyVault::Keys::DeleteKeyOperation KeyClient::StartDeleteKey(
|
||||
},
|
||||
{_detail::KeysPath, name}));
|
||||
}
|
||||
|
||||
Azure::Response<DeletedKey> KeyClient::GetDeletedKey(
|
||||
std::string const& name,
|
||||
Azure::Core::Context const& context) const
|
||||
{
|
||||
return m_pipeline->SendRequest<DeletedKey>(
|
||||
context,
|
||||
Azure::Core::Http::HttpMethod::Get,
|
||||
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
|
||||
return _detail::DeletedKeyDeserialize(name, rawResponse);
|
||||
},
|
||||
{_detail::DeletedKeysPath, name});
|
||||
}
|
||||
|
||||
@ -8,8 +8,11 @@
|
||||
#include <azure/keyvault/common/internal/unix_time_helper.hpp>
|
||||
|
||||
#include <azure/core/internal/json/json.hpp>
|
||||
#include <azure/core/internal/json/json_optional.hpp>
|
||||
#include <azure/core/internal/json/json_serializable.hpp>
|
||||
|
||||
using namespace Azure::Security::KeyVault::Keys;
|
||||
using namespace Azure::Core::Json::_internal;
|
||||
using Azure::Security::KeyVault::Common::_internal::UnixTimeConverter;
|
||||
|
||||
namespace {
|
||||
@ -38,39 +41,61 @@ void _detail::KeyVaultKeyDeserialize(
|
||||
Azure::Core::Http::RawResponse const& rawResponse)
|
||||
{
|
||||
auto body = rawResponse.GetBody();
|
||||
auto jsonParser = Azure::Core::Json::_internal::json::parse(body);
|
||||
auto jsonParser = json::parse(body);
|
||||
|
||||
// "Key"
|
||||
auto const& jsonKey = jsonParser[_detail::KeyPropertyName];
|
||||
if (jsonParser.contains(_detail::KeyPropertyName))
|
||||
{
|
||||
// key_ops
|
||||
auto keyOperationVector = jsonKey[_detail::KeyOpsPropertyName].get<std::vector<std::string>>();
|
||||
std::vector<KeyOperation> keyOperations;
|
||||
ParseStringOperationsToKeyOperations(keyOperations, keyOperationVector);
|
||||
key.Key.SetKeyOperations(keyOperations);
|
||||
}
|
||||
key.Key.Id = jsonKey[_detail::KeyIdPropertyName].get<std::string>();
|
||||
key.Key.KeyType
|
||||
= _detail::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get<std::string>());
|
||||
auto const& jsonKey = jsonParser[_detail::KeyPropertyName];
|
||||
{
|
||||
// key_ops
|
||||
auto keyOperationVector
|
||||
= jsonKey[_detail::KeyOpsPropertyName].get<std::vector<std::string>>();
|
||||
std::vector<KeyOperation> keyOperations;
|
||||
ParseStringOperationsToKeyOperations(keyOperations, keyOperationVector);
|
||||
key.Key.SetKeyOperations(keyOperations);
|
||||
}
|
||||
key.Key.Id = jsonKey[_detail::KeyIdPropertyName].get<std::string>();
|
||||
key.Key.KeyType
|
||||
= _detail::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get<std::string>());
|
||||
|
||||
if (jsonKey.contains(_detail::CurveNamePropertyName))
|
||||
{
|
||||
key.Key.CurveName = KeyCurveName(jsonKey[_detail::CurveNamePropertyName].get<std::string>());
|
||||
JsonOptional::SetIfExists<std::string, KeyCurveName>(
|
||||
key.Key.CurveName, jsonKey, _detail::CurveNamePropertyName, [](std::string const& keyName) {
|
||||
return KeyCurveName(keyName);
|
||||
});
|
||||
}
|
||||
|
||||
// "Attributes"
|
||||
if (jsonParser.contains(_detail::AttributesPropertyName))
|
||||
{
|
||||
auto attributes = jsonParser[_detail::AttributesPropertyName];
|
||||
key.Properties.CreatedOn
|
||||
= UnixTimeConverter::UnixTimeToDatetime(attributes["created"].get<uint64_t>());
|
||||
|
||||
JsonOptional::SetIfExists(key.Properties.Enabled, attributes, "enabled");
|
||||
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
|
||||
key.Properties.NotBefore, attributes, "nbf", UnixTimeConverter::UnixTimeToDatetime);
|
||||
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
|
||||
key.Properties.ExpiresOn, attributes, "exp", UnixTimeConverter::UnixTimeToDatetime);
|
||||
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
|
||||
key.Properties.CreatedOn, attributes, "created", UnixTimeConverter::UnixTimeToDatetime);
|
||||
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
|
||||
key.Properties.UpdatedOn, attributes, "updated", UnixTimeConverter::UnixTimeToDatetime);
|
||||
}
|
||||
|
||||
// "Tags"
|
||||
auto const& tags = jsonParser[_detail::TagsPropertyName];
|
||||
if (jsonParser.contains(_detail::TagsPropertyName))
|
||||
{
|
||||
for (auto tag = tags.begin(); tag != tags.end(); ++tag)
|
||||
auto const& tags = jsonParser[_detail::TagsPropertyName];
|
||||
{
|
||||
key.Properties.Tags.emplace(tag.key(), tag.value().get<std::string>());
|
||||
for (auto tag = tags.begin(); tag != tags.end(); ++tag)
|
||||
{
|
||||
key.Properties.Tags.emplace(tag.key(), tag.value().get<std::string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// managed
|
||||
if (jsonParser.contains(_detail::ManagedPropertyName))
|
||||
{
|
||||
key.Properties.Managed = jsonParser[_detail::ManagedPropertyName].get<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +132,7 @@ TEST_F(KeyVaultClientTest, CreateEcKeyWithCurve)
|
||||
CheckValidResponse(keyResponse);
|
||||
auto keyVaultKey = keyResponse.ExtractValue();
|
||||
EXPECT_EQ(keyVaultKey.Name(), keyName);
|
||||
EXPECT_EQ(ecKey.CurveName->ToString(), keyVaultKey.Key.CurveName->ToString());
|
||||
}
|
||||
{
|
||||
// Now get the key
|
||||
|
||||
@ -271,3 +271,38 @@ TEST_F(KeyVaultClientTest, CreateDeletedKeyBeforePollComplete)
|
||||
}
|
||||
EXPECT_TRUE(wasThrown);
|
||||
}
|
||||
|
||||
// Get Delete Key
|
||||
TEST_F(KeyVaultClientTest, GetDeletedKey)
|
||||
{
|
||||
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
|
||||
std::string keyName("deleteThisKeyAndGetItFromDeleteKeys1wwxx3x4");
|
||||
|
||||
{
|
||||
auto keyResponse
|
||||
= keyClient.CreateKey(keyName, Azure::Security::KeyVault::Keys::JsonWebKeyType::Ec);
|
||||
CheckValidResponse(keyResponse);
|
||||
auto keyVaultKey = keyResponse.ExtractValue();
|
||||
EXPECT_EQ(keyVaultKey.Name(), keyName);
|
||||
}
|
||||
{
|
||||
// Wait until key is deleted
|
||||
auto duration = std::chrono::system_clock::now() + std::chrono::minutes(3);
|
||||
auto cancelToken = Azure::Core::Context::GetApplicationContext().WithDeadline(duration);
|
||||
|
||||
auto keyResponseLRO = keyClient.StartDeleteKey(keyName);
|
||||
auto expectedStatusToken = m_keyVaultUrl + "/"
|
||||
+ std::string(Azure::Security::KeyVault::Keys::_detail::DeletedKeysPath) + "/" + keyName;
|
||||
auto keyResponse = keyResponseLRO.PollUntilDone(std::chrono::milliseconds(1000), cancelToken);
|
||||
}
|
||||
{
|
||||
// Get the deleted key
|
||||
auto deletedKey = keyClient.GetDeletedKey(keyName).ExtractValue();
|
||||
EXPECT_FALSE(deletedKey.RecoveryId.empty());
|
||||
EXPECT_EQ(deletedKey.Name(), keyName);
|
||||
auto expectedType = Azure::Security::KeyVault::Keys::JsonWebKeyType::Ec;
|
||||
EXPECT_EQ(
|
||||
Azure::Security::KeyVault::Keys::_detail::KeyTypeToString(expectedType),
|
||||
Azure::Security::KeyVault::Keys::_detail::KeyTypeToString(deletedKey.Key.KeyType));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user