[Keyvault] APIs (#1967)

Adding the next APIs:

UpdateKeyProperties, fixes: #1541
GetPropertiesOfKeys , fixes: #1542
GetPropertiesOfKeyVersions, fixes: #1543
GetDeletedKeys, fixes: #1546
PurgeDeletedKey, fixes: #1547
StartRecoveryDeletedKey, fixes: #1548
BackupKey, fixes: #1549
RestoreKeyBackup, fixes: #1550
ImportKey, fixes: #1551
Add samples, fixes: #1987
This commit is contained in:
Victor Vazquez 2021-03-30 13:12:48 -07:00 committed by GitHub
parent 7490709db4
commit a4ae81708b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 2885 additions and 261 deletions

View File

@ -25,7 +25,7 @@ namespace Azure { namespace Core { namespace Json { namespace _internal {
{
/**
* @brief If the optional key \p key is present in the json node \p jsonKey set the value of \p
* destination.
* the Nullable destination.
*
* @remark If the key is not in the json node, the \p destination is not modified.
*
@ -39,7 +39,7 @@ namespace Azure { namespace Core { namespace Json { namespace _internal {
Azure::Core::Json::_internal::json const& jsonKey,
std::string const& key) noexcept
{
if (jsonKey.contains(key))
if (jsonKey.contains(key) && !jsonKey[key].is_null()) // In Json and not-Null
{
destination = jsonKey[key].get<T>();
}
@ -54,6 +54,36 @@ namespace Azure { namespace Core { namespace Json { namespace _internal {
* @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 callback used to convert the Json value from `V` type to the `T` type. For
* example, getting std::string from Json (the V type) and setting a Nullable<Datatime> (where T
* type is Datetime), the decorator would define how to create the Datetime from the
* std::string.
*/
template <class V, class T>
static inline void SetIfExists(
T& destination,
Azure::Core::Json::_internal::json const& jsonKey,
std::string const& key,
std::function<T(V value)> decorator) noexcept
{
if (jsonKey.contains(key))
{
if (!jsonKey[key].is_null())
{
destination = decorator(jsonKey[key].get<V>());
}
}
}
/**
* @brief If the optional key \p key is present in the json node \p jsonKey set the value of \p
* the Nullable 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.
*/
@ -71,4 +101,29 @@ namespace Azure { namespace Core { namespace Json { namespace _internal {
}
};
template <class T, class R>
static inline void SetFromNullable(
Azure::Nullable<T> const& source,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName,
std::function<R(T const&)> factory)
{
if (source)
{
jsonKey[keyName] = factory(source.GetValue());
}
}
template <class T>
static inline void SetFromNullable(
Azure::Nullable<T> const& source,
Azure::Core::Json::_internal::json& jsonKey,
std::string const& keyName)
{
if (source)
{
jsonKey[keyName] = source.GetValue();
}
}
}}}} // namespace Azure::Core::Json::_internal

View File

@ -25,6 +25,12 @@ namespace Azure { namespace Core { namespace Json { namespace _internal {
* @return The json string representation.
*/
virtual std::string Serialize() const = 0;
/**
* @brief Default destructor for serializable objects.
*
*/
virtual ~JsonSerializable() = default;
};
}}}} // namespace Azure::Core::Json::_internal

View File

@ -243,6 +243,13 @@ namespace Azure { namespace Core {
*/
std::string GetUrlWithoutQuery() const { return GetUrlWithoutQuery(false); }
/**
* @brief Get Scheme, host and port.
*
* @return Url authority.
*/
std::string GetUrlAuthorityWithScheme() const;
/**
* @brief Get the path and query parameters.
*

View File

@ -178,21 +178,29 @@ void Url::AppendQueryParameters(const std::string& query)
}
}
std::string Url::GetUrlAuthorityWithScheme() const
{
std::string url;
if (!m_scheme.empty())
{
url += m_scheme + "://";
}
url += m_host;
if (m_port != 0)
{
url += ":" + std::to_string(m_port);
}
return url;
}
std::string Url::GetUrlWithoutQuery(bool relative) const
{
std::string url;
if (!relative)
{
if (!m_scheme.empty())
{
url += m_scheme + "://";
}
url += m_host;
if (m_port != 0)
{
url += ":" + std::to_string(m_port);
}
url += GetUrlAuthorityWithScheme();
}
if (!m_encodedPath.empty())

View File

@ -59,7 +59,7 @@ namespace Azure { namespace Perf { namespace Test {
Azure::Core::Http::Request request(Azure::Core::Http::HttpMethod::Get, m_url);
auto response = _detail::HttpClient->Send(request, ctx);
// Read the body from network
auto bodyStream = response->GetBodyStream();
auto bodyStream = response->ExtractBodyStream();
response->SetBody(bodyStream->ReadToEnd(ctx));
}

View File

@ -28,8 +28,10 @@ endif()
set(
AZURE_KEYVAULT_COMMON_HEADER
inc/azure/keyvault/common/internal/base64url.hpp
inc/azure/keyvault/common/internal/keyvault_pipeline.hpp
inc/azure/keyvault/common/internal/unix_time_helper.hpp
inc/azure/keyvault/common/client_options.hpp
inc/azure/keyvault/common/keyvault_constants.hpp
inc/azure/keyvault/common/keyvault_exception.hpp
inc/azure/keyvault/common/version.hpp

View File

@ -0,0 +1,75 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Defines the base options to create a Key Vault client.
*
*/
#pragma once
#include <azure/core/internal/client_options.hpp>
#include <stdexcept>
#include <string>
namespace Azure { namespace Security { namespace KeyVault { namespace Common {
/**
* @brief Available and supported service versions.
*
*/
enum class ServiceVersion
{
/**
* @brief Use to send request to the 7.0 version of Key Vault service.
*
*/
V7_0,
/**
* @brief Use to send request to the 7.1 version of Key Vault service.
*
*/
V7_1,
/**
* @brief Use to send request to the 7.2 version of Key Vault service.
*
*/
V7_2
};
/**
* @brief Define the base options to create an KeyVault SDK client.
*
*/
struct ClientOptions : public Azure::Core::_internal::ClientOptions
{
/**
* @brief The service version. All request are created with this version.
*
*/
ServiceVersion Version;
ClientOptions(ServiceVersion version)
: Azure::Core::_internal::ClientOptions(), Version(version)
{
}
std::string GetVersionString() const
{
switch (Version)
{
case ServiceVersion::V7_0:
return "7.0";
case ServiceVersion::V7_1:
return "7.1";
case ServiceVersion::V7_2:
return "7.2";
default:
throw std::runtime_error("Version not found");
}
}
};
}}}} // namespace Azure::Security::KeyVault::Common

View File

@ -0,0 +1,59 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @brief Provides helper method for base64url.
*
*/
#pragma once
#include <algorithm>
#include <azure/core/base64.hpp>
#include <stdexcept>
#include <string>
namespace Azure { namespace Security { namespace KeyVault { namespace Common { namespace _internal {
/**
* @brief Provides conversion methods for base64url.
*/
struct Base64Url
{
static inline std::string Base64UrlEncode(const std::vector<uint8_t>& data)
{
auto base64 = Azure::Core::Convert::Base64Encode(data);
// update to base64url
auto trail = base64.find('=');
if (trail != std::string::npos)
{
base64 = base64.substr(0, trail);
}
std::replace(base64.begin(), base64.end(), '+', '-');
std::replace(base64.begin(), base64.end(), '/', '_');
return base64;
}
static inline std::vector<uint8_t> Base64UrlDecode(const std::string& text)
{
std::string base64url(text);
// base64url to base64
std::replace(base64url.begin(), base64url.end(), '-', '+');
std::replace(base64url.begin(), base64url.end(), '_', '/');
switch (base64url.size() % 4)
{
case 0:
break;
case 2:
base64url.append("==");
break;
case 3:
base64url.append("=");
break;
default:
throw new std::invalid_argument("Unexpected base64 encoding in the http response.");
}
return Azure::Core::Convert::Base64Decode(base64url);
}
};
}}}}} // namespace Azure::Security::KeyVault::Common::_internal

View File

@ -90,6 +90,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Common { n
* @param method The method for the request.
* @param factoryFn The function to deserialize and produce T from the raw response.
* @param path A path for the request represented as a vector of strings.
* @param query Optional query parameters for constructing the request.
* @return The object produced by the \p factoryFn and the raw response from the network.
*/
template <class T>
@ -97,9 +98,17 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Common { n
Azure::Core::Context const& context,
Azure::Core::Http::HttpMethod method,
std::function<T(Azure::Core::Http::RawResponse const& rawResponse)> factoryFn,
std::vector<std::string> const& path)
std::vector<std::string> const& path,
std::unique_ptr<std::map<std::string, std::string>> const& query = nullptr)
{
auto request = CreateRequest(method, path);
if (query != nullptr)
{
for (auto const& queryParameter : *query)
{
request.GetUrl().AppendQueryParameter(queryParameter.first, queryParameter.second);
}
}
auto response = SendRequest(context, request);
return Azure::Response<T>(factoryFn(*response), std::move(response));
}
@ -132,6 +141,23 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Common { n
return Azure::Response<T>(factoryFn(*response), std::move(response));
}
template <class T>
Azure::Response<T> SendRequest(
Azure::Core::Context const& context,
Azure::Core::Http::HttpMethod method,
std::function<std::string()> serializeContentFn,
std::function<T(Azure::Core::Http::RawResponse const& rawResponse)> factoryFn,
std::vector<std::string> const& path)
{
auto serialContent = serializeContentFn();
auto streamContent = Azure::Core::IO::MemoryBodyStream(
reinterpret_cast<const uint8_t*>(serialContent.data()), serialContent.size());
auto request = CreateRequest(method, &streamContent, path);
auto response = SendRequest(context, request);
return Azure::Response<T>(factoryFn(*response), std::move(response));
}
/**
* @brief Create a key vault request and send it using the Azure Core pipeline directly to avoid
* checking the respone code.

View File

@ -29,5 +29,18 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Common { n
{
return Azure::DateTime(1970) + std::chrono::seconds(unixTime);
}
/**
* @brief Converts a #Azure::Core::Datetime to unix time.
*
* @param dateTime The date time to convert.
*/
static inline uint64_t DatetimeToUnixTime(Azure::DateTime dateTime)
{
// This count starts at the Unix Epoch which was January 1st, 1970 at UTC.
auto secondsSince1970
= std::chrono::duration_cast<std::chrono::seconds>(dateTime - Azure::DateTime(1970));
return secondsSince1970.count();
}
};
}}}}} // namespace Azure::Security::KeyVault::Common::_internal

View File

@ -30,17 +30,21 @@ set(
AZURE_KEYVAULT_KEYS_HEADER
inc/azure/keyvault/keys/delete_key_operation.hpp
inc/azure/keyvault/keys/deleted_key.hpp
inc/azure/keyvault/keys/details/key_backup.hpp
inc/azure/keyvault/keys/details/key_constants.hpp
inc/azure/keyvault/keys/details/key_request_parameters.hpp
inc/azure/keyvault/keys/import_key_options.hpp
inc/azure/keyvault/keys/json_web_key.hpp
inc/azure/keyvault/keys/key_client.hpp
inc/azure/keyvault/keys/details/key_constants.hpp
inc/azure/keyvault/keys/key_create_options.hpp
inc/azure/keyvault/keys/key_curve_name.hpp
inc/azure/keyvault/keys/key_client_options.hpp
inc/azure/keyvault/keys/key_operation.hpp
inc/azure/keyvault/keys/key_properties.hpp
inc/azure/keyvault/keys/details/key_request_parameters.hpp
inc/azure/keyvault/keys/key_type.hpp
inc/azure/keyvault/keys/key_vault_key.hpp
inc/azure/keyvault/keys/list_keys_single_page_result.hpp
inc/azure/keyvault/keys/recover_deleted_key_operation.hpp
inc/azure/keyvault/keys/version.hpp
)
@ -48,11 +52,16 @@ set(
AZURE_KEYVAULT_KEYS_SOURCE
src/delete_key_operation.cpp
src/deleted_key.cpp
src/import_key_options.cpp
src/json_web_key.cpp
src/key_backup.cpp
src/key_client.cpp
src/key_curve_name.cpp
src/key_request_parameters.cpp
src/key_type.cpp
src/key_vault_key.cpp
src/list_keys_single_page_result.cpp
src/recover_deleted_key_operation.cpp
)
add_library(azure-security-keyvault-keys
@ -90,7 +99,7 @@ if (BUILD_PERFORMANCE_TESTS)
endif()
if(BUILD_SAMPLES)
add_subdirectory(sample)
add_subdirectory(test/samples)
endif()
az_vcpkg_export(

View File

@ -11,10 +11,16 @@
#include "azure/keyvault/keys/delete_key_operation.hpp"
#include "azure/keyvault/keys/deleted_key.hpp"
#include "azure/keyvault/keys/dll_import_export.hpp"
#include "azure/keyvault/keys/import_key_options.hpp"
#include "azure/keyvault/keys/json_web_key.hpp"
#include "azure/keyvault/keys/key_client.hpp"
#include "azure/keyvault/keys/key_client_options.hpp"
#include "azure/keyvault/keys/key_create_options.hpp"
#include "azure/keyvault/keys/key_curve_name.hpp"
#include "azure/keyvault/keys/key_operation.hpp"
#include "azure/keyvault/keys/key_properties.hpp"
#include "azure/keyvault/keys/key_type.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
#include "azure/keyvault/keys/list_keys_single_page_result.hpp"
#include "azure/keyvault/keys/recover_deleted_key_operation.hpp"
#include "azure/keyvault/keys/version.hpp"

View File

@ -53,12 +53,4 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
*/
Azure::DateTime ScheduledPurgeDate;
};
/*********************** Deserializer / Serializer ******************************/
namespace _detail {
DeletedKey DeletedKeyDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse);
} // namespace _detail
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Internal wrapper layer on top of a uint_8 array.
*
*/
#pragma once
#include <azure/core/http/http.hpp>
#include <azure/core/internal/json/json_serializable.hpp>
#include <string>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys { namespace _detail {
struct KeyBackup : public Azure::Core::Json::_internal::JsonSerializable
{
std::vector<uint8_t> Value;
std::string Serialize() const override;
static KeyBackup Deserialize(Azure::Core::Http::RawResponse const& rawResponse);
};
}}}}} // namespace Azure::Security::KeyVault::Keys::_detail

View File

@ -22,6 +22,13 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam
constexpr static const char AttributesPropertyName[] = "attributes";
constexpr static const char TagsPropertyName[] = "tags";
constexpr static const char ReleasePolicyPropertyName[] = "release_policy";
constexpr static const char EnabledPropertyName[] = "enabled";
constexpr static const char NbfPropertyName[] = "nbf";
constexpr static const char ExpPropertyName[] = "exp";
constexpr static const char CreatedPropertyName[] = "created";
constexpr static const char UpdatedPropertyName[] = "updated";
constexpr static const char RecoverableDaysPropertyName[] = "recoverableDays";
constexpr static const char RecoveryLevelPropertyName[] = "recoveryLevel";
/***************** Key Request Parameters *****************/
constexpr static const char KeyTypePropertyName[] = "kty";
@ -69,4 +76,21 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam
constexpr static const char P384OidValue[] = "1.3.132.0.34";
constexpr static const char P521OidValue[] = "1.3.132.0.35";
/***************** Import Key *****************/
constexpr static const char HsmPropertyName[] = "hsm";
/***************** Encryption Algorithm *********/
constexpr static const char Rsa15Value[] = "RSA1_5";
constexpr static const char RsaOaepValue[] = "RSA-OAEP";
constexpr static const char RsaOaep256Value[] = "RSA-OAEP-256";
constexpr static const char A128GcmValue[] = "A128GCM";
constexpr static const char A192GcmValue[] = "A192GCM";
constexpr static const char A256GcmValue[] = "A256GCM";
constexpr static const char A128CbcValue[] = "A128CBC";
constexpr static const char A192CbcValue[] = "A192CBC";
constexpr static const char A256CbcValue[] = "A256CBC";
constexpr static const char A128CbcPadValue[] = "A128CBCPAD";
constexpr static const char A192CbcPadValue[] = "A192CBCPAD";
constexpr static const char A256CbcPadValue[] = "A256CBCPAD";
}}}}} // namespace Azure::Security::KeyVault::Keys::_detail

View File

@ -17,22 +17,51 @@
#include "azure/keyvault/keys/key_type.hpp"
#include <functional>
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys { namespace _detail {
class KeyRequestParameters : public Azure::Core::Json::_internal::JsonSerializable {
private:
JsonWebKeyType m_keyType;
CreateKeyOptions const& m_options;
Azure::Nullable<JsonWebKeyType> m_keyType;
CreateKeyOptions m_options;
public:
Azure::Nullable<KeyCurveName> Curve;
Azure::Nullable<uint64_t> KeySize;
Azure::Nullable<uint64_t> PublicExponent;
explicit KeyRequestParameters(
KeyProperties const& key,
Azure::Nullable<std::list<KeyOperation>> const& operations)
: m_options(CreateKeyOptions())
{
if (key.Enabled)
{
m_options.Enabled = key.Enabled.GetValue();
}
if (key.ExpiresOn)
{
m_options.ExpiresOn = key.ExpiresOn.GetValue();
}
if (key.NotBefore)
{
m_options.NotBefore = key.NotBefore.GetValue();
}
if (key.Tags.size() > 0)
{
m_options.Tags = std::unordered_map<std::string, std::string>(key.Tags);
}
if (operations)
{
m_options.KeyOperations = std::list<KeyOperation>(operations.GetValue());
}
}
explicit KeyRequestParameters(JsonWebKeyType keyType, CreateKeyOptions const& options)
: m_keyType(keyType), m_options(options)
{

View File

@ -0,0 +1,93 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Centralize the serialize and de-serialize methods for the key vault keys models.
*
*/
#pragma once
#include <azure/core/internal/json/json.hpp>
#include "azure/keyvault/keys/deleted_key.hpp"
#include "azure/keyvault/keys/import_key_options.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
#include "azure/keyvault/keys/list_keys_single_page_result.hpp"
#include <string>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys { namespace _detail {
/***************** KeyVault Key *****************/
struct KeyVaultKeySerializer
{
// Creates a new key based on a name and an http raw response.
static KeyVaultKey KeyVaultKeyDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse);
// Create from http raw response only.
static KeyVaultKey KeyVaultKeyDeserialize(Azure::Core::Http::RawResponse const& rawResponse);
// Updates a Key based on an Http raw response.
static void KeyVaultKeyDeserialize(
KeyVaultKey& key,
Azure::Core::Http::RawResponse const& rawResponse);
// Create from json node directly. Used from listKeys
static void KeyVaultKeyDeserialize(
KeyVaultKey& key,
Azure::Core::Json::_internal::json const& json);
void static inline ParseKeyUrl(KeyProperties& keyProperties, std::string const& url)
{
Azure::Core::Url kid(url);
keyProperties.Id = url;
keyProperties.VaultUrl = kid.GetUrlAuthorityWithScheme();
auto const& path = kid.GetPath();
// path is in the form of `verb/keyName{/keyVersion}`
auto const separatorChar = '/';
auto pathEnd = path.end();
auto start = path.begin();
start = std::find(start, pathEnd, separatorChar);
start += 1;
auto separator = std::find(start, pathEnd, separatorChar);
if (separator != pathEnd)
{
keyProperties.Name = std::string(start, separator);
start = separator + 1;
keyProperties.Version = std::string(start, pathEnd);
}
else
{
// Nothing but the name+
keyProperties.Name = std::string(start, pathEnd);
}
}
};
/**************** Deleted Key *******************/
struct DeletedKeySerializer
{
static DeletedKey DeletedKeyDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse);
};
/**************** Import Key Options ***********/
struct ImportKeyOptionsSerializer
{
static std::string ImportKeyOptionsSerialize(ImportKeyOptions const& importKeyOptions);
};
/**************** Key Properties Single Page ************/
struct KeyPropertiesSinglePageSerializer
{
static KeyPropertiesSinglePage KeyPropertiesSinglePageDeserialize(
Azure::Core::Http::RawResponse const& rawResponse);
static DeletedKeySinglePage DeletedKeySinglePageDeserialize(
Azure::Core::Http::RawResponse const& rawResponse);
};
}}}}} // namespace Azure::Security::KeyVault::Keys::_detail

View File

@ -0,0 +1,66 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Defines the properties to import a Key.
*
*/
#pragma once
#include <azure/core/nullable.hpp>
#include "azure/keyvault/keys/json_web_key.hpp"
#include "azure/keyvault/keys/key_operation.hpp"
#include "azure/keyvault/keys/key_properties.hpp"
#include <azure/core/http/http.hpp>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
/**
* @brief A key resource and its properties.
*
*/
struct ImportKeyOptions
{
/**
* @brief The cryptographic key, the key type, and the operations you can perform using the key.
*
*/
JsonWebKey Key;
/**
* @brief The additional properties.
*
*/
KeyProperties Properties;
/**
* @brief Get or Set a value indicating whether to import the key into a hardware security
* module (HSM).
*
*/
Azure::Nullable<bool> HardwareProtected;
/**
* @brief Construct a new Key Vault ImportKeyOptions object.
*
* @param name The name of the key.
*/
ImportKeyOptions(std::string name, JsonWebKey keyMaterial)
: Key(keyMaterial), Properties(std::move(name))
{
}
/**
* @brief Gets the name of the Key.
*
* @return The name of the key.
*/
std::string const& Name() const { return Properties.Name; }
};
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -9,6 +9,7 @@
#pragma once
#include <azure/core/internal/json/json.hpp>
#include <azure/core/nullable.hpp>
#include "azure/keyvault/keys/key_curve_name.hpp"
@ -71,8 +72,31 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
*/
Azure::Nullable<KeyCurveName> CurveName;
/**** RSA fields ****/
/// The RSA modulus.
std::vector<uint8_t> N;
/// The RSA public exponent.
std::vector<uint8_t> E;
/// The RSA private key parameter.
std::vector<uint8_t> DP;
/// The RSA private key parameter.
std::vector<uint8_t> DQ;
/// The RSA private key parameter.
std::vector<uint8_t> QI;
/// The RSA secret prime.
std::vector<uint8_t> P;
/// The RSA secret prime.
std::vector<uint8_t> Q;
/// The RSA private exponent or EC private key.
std::vector<uint8_t> D;
private:
std::vector<KeyOperation> m_keyOps;
};
// Define the serialization of a JsonWebKey
void to_json(Azure::Core::Json::_internal::json& j, JsonWebKey const& p);
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -12,16 +12,44 @@
#include <azure/keyvault/common/internal/keyvault_pipeline.hpp>
#include "azure/keyvault/keys/delete_key_operation.hpp"
#include "azure/keyvault/keys/import_key_options.hpp"
#include "azure/keyvault/keys/key_client_options.hpp"
#include "azure/keyvault/keys/key_create_options.hpp"
#include "azure/keyvault/keys/key_type.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
#include "azure/keyvault/keys/list_keys_single_page_result.hpp"
#include "azure/keyvault/keys/recover_deleted_key_operation.hpp"
#include <functional>
#include <list>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
/**
* @brief Define a model for a purged key.
*
*/
struct PurgedKey
{
};
/**
* @brief Optional parameters for KeyVaultClient::GetKey
*
*/
struct GetKeyOptions
{
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
/**
* @brief Specify the key version to get.
*/
std::string Version;
};
/**
* @brief The KeyClient provides synchronous methods to manage a KeyVaultKe in the Azure Key
* Vault. The client supports creating, retrieving, updating, deleting, purging, backing up,
@ -45,22 +73,6 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
KeyClientOptions options = KeyClientOptions());
/**
* @brief Optional parameters for KeyVaultClient::GetKey
*
*/
struct GetKeyOptions
{
/**
* @brief Context for cancelling long running operations.
*/
Azure::Core::Context Context;
/**
* @brief Specify the key version to get.
*/
std::string Version;
};
/**
* @brief Gets the public part of a stored key.
*
@ -145,6 +157,55 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
CreateOctKeyOptions const& octKeyOptions,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Get a single page with the properties of all keys in the specified vault. You can use
* the returned #KeyProperties.Name in subsequent calls to #GetKey.
*
* @remark Retrieves a list of the keys in the Key Vault that contains the public part of a
* stored key. The operation is applicable to all key types, however only the base key
* identifier, attributes, and tags are provided in the response. Individual versions of a key
* are not listed in the response. This operation requires the keys/list permission.
*
* @remark Use \p options to control which page to get. If
* #GetPropertiesOfKeysSinglePageOptions.NextLink is not set, the operation will get the first
* page and it will set the `ContinuationToken` from the #KeyPropertiesSinglePage as the next
* page of the response if there is a next page.
*
* @param options The #GetPropertiesOfKeysSinglePageOptions object to for setting the operation
* up.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<KeyPropertiesSinglePage>
*/
Azure::Response<KeyPropertiesSinglePage> GetPropertiesOfKeysSinglePage(
GetPropertiesOfKeysSinglePageOptions const& options
= GetPropertiesOfKeysSinglePageOptions(),
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Get one page listing the properties of all the versions of the specified key. You can
* use the returned #KeyProperties.Name and #KeyProperties.Version in subsequent calls to
* #GetKey.
*
* @remark The full identifier, attributes, and tags are provided in the response. This
* operation requires the keys/list permission.
*
* @remark Use \p options to control which page to get. If
* #GetPropertiesOfKeyVersionsSinglePageOptions.NextLink is not set, the operation will get the
* first page and it will set the `ContinuationToken` from the #KeyPropertiesSinglePage as the
* next page of the response if there is a next page.
*
* @param name The name of the key.
* @param options The #GetPropertiesOfKeyVersionsSinglePageOptions object to for setting the
* operation up.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<KeyPropertiesSinglePage>
*/
Azure::Response<KeyPropertiesSinglePage> GetPropertiesOfKeyVersionsSinglePage(
std::string const& name,
GetPropertiesOfKeyVersionsSinglePageOptions const& options
= GetPropertiesOfKeyVersionsSinglePageOptions(),
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Deletes a key of any type from storage in Azure Key Vault.
*
@ -178,5 +239,156 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
Azure::Response<DeletedKey> GetDeletedKey(
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Get on page listing the deleted keys in the specified vault.
*
* @remark Retrieves a list of the keys in the Key Vault that contains the public part od the
* deleted key. This operation includes deletion-specific information. This operation is
* applicable for vaults enabled fr soft-delete. While the operation can be invoked on any
* vault, it will return error if invoked on a non soft-delete enabled vault. This operation
* requires the keys/list permission.
*
* @remark Use \p options to control which page to get. If
* #GetPropertiesOfKeyVersionsSinglePageOptions.NextLink is not set, the operation will get the
* first page and it will set the `ContinuationToken` from the #KeyPropertiesSinglePage as the
* next page of the response if there is a next page.
*
* @param options The #GetDeletedKeysSinglePageOptions object to for setting the operation up.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<DeletedKeySinglePage>
*/
Azure::Response<DeletedKeySinglePage> GetDeletedKeysSinglePage(
GetDeletedKeysSinglePageOptions const& options = GetDeletedKeysSinglePageOptions(),
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Permanently deletes the specified key.
*
* @remark The Purge Deleted Key operation is applicable for soft-delete enabled values. 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/purge permission.
*
* @param name The name of the key.
* @param context A #Azure::Core::Context controlling the request lifetime.
*/
Azure::Response<PurgedKey> PurgeDeletedKey(
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Recovers the deleted key to its latest version.
*
* @remark The Recover Deleted Key operation is applicable for deleted keys in soft-delete
* enabled vaults. It recovers the deleted key back to its latest version under /keys. An
* attempt to recover an non-deleted key will return an error. Consider this the inverse of the
* delete operation on soft-delete enabled vaults. This operation requires the keys/recover
* permission.
*
* @param name The name of the key.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation
*/
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation StartRecoverDeletedKey(
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief The update key operation changes specified attributes of a stored key and can be
* applied to any key type and key version stored in Azure Key Vault.
*
* @remark In order to perform this operation, the key must already exist in the Key Vault.
* Note: The cryptographic material of a key itself cannot be changed. This operation requires
* the keys/update permission.
*
* @param properties The #KeyProperties object with updated properties.
* @param keyOperations Optional list of supported #KeyOperation. If no operation list provided,
* no changes will be made to existing key operations.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<KeyVaultKey>
*/
Azure::Response<KeyVaultKey> UpdateKeyProperties(
KeyProperties const& properties,
Azure::Nullable<std::list<KeyOperation>> const& keyOperations
= Azure::Nullable<std::list<KeyOperation>>(),
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Request that a backup of the specified be downloaded to the client.
*
* @remark The Key Backup operation exports a key from Azure Key Vault in a protected form. Note
* that this operation does NOT return the actual key in a form that can be used outside the
* Azure Key Vault system, the returned key is either protected to a Azure Key Vault HSM or to
* Azure Key Vault itself. The intent of this operation is to allow a client to GENERATE a key
* in one Azure Key Vault instance, BACKUP the key, and then RESTORE it into another Azure Key
* Vault instance. The BACKUP operation may be used to export, in protected form, any key type
* from Azure Key Vault. Individual versions of a key cannot be backed up. BACKUP / RESTORE can
* be performed within geographical boundaries only; meaning that a BACKUP from one geographical
* are cannot be restored to another geographical are. For example, a backup from the US
* geographical are cannot be restored in an EU geographical area. This operation requires the
* key/backup permission.
*
* @param name The name of the key.
* @param context A #Azure::Core::Context controlling the request lifetime.
*/
Azure::Response<std::vector<uint8_t>> BackupKey(
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Restores a backed up key to keyvault.
*
* @remark Imports a previously backed up key into Azure Key Vault, restoring the key, its key
* identifier, attributes, and access control policies. The RESTORE operation may be used to
* import a previously backed up key. Individual versions of a key cannot be restored. The key
* is restored in its entirety with the same key name as it had when it was backed up. If the
* key name is not available in the target Key Vault, the RESTORE operation will be rejected.
* While the key name is retained during restore, the final key identifier will change if the
* key is restored to a different vault. Restore will restore all versions and preserve version
* identifiers. The RESTORE operation is subject to security constrains: The target Key Vault
* must be owned by the same Microsoft Azure Subscription as the source Key Vault. The user must
* have RESTORE permission in the target Key Vault. This operation requires the keys/restore
* permission.
*
* @param backup The backup blob associated with a key.
* @param context A #Azure::Core::Context controlling the request lifetime.
*/
Azure::Response<KeyVaultKey> RestoreKeyBackup(
std::vector<uint8_t> const& backup,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Imports an externally created ket, stores it, and returns jey parameters and
* attributes to the client.
*
* @remark The import key operation may be used to import any key type into an Azure Key Vault.
* If the named key already exists, Azure Key Vault creates a new version of the key. This
* operation requires the keys/import permission.
*
* @param name The name of the key.
* @param keyMaterial The #JsonWebKey being imported.
* @param context A #Azure::Core::Context controlling the request lifetime.
* @return Azure::Response<KeyVaultKey>
*/
Azure::Response<KeyVaultKey> ImportKey(
std::string const& name,
JsonWebKey const& keyMaterial,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Imports an externally created key, stores it, and returns key parameters and
* attributes to the client.
*
* @remark The import operation may be used to import any key type into an Azure Key Vault. If
* the named key already exists, Azure Key Vault creates a new version of the key. This
* operation requires the keys/import permission.
*
* @param importKeyOptions The key import configuration object containing information about the
* #JsonWebKey being imported.
* @param context A #Azure::Core::Context controlling the request lifetime.
*/
Azure::Response<KeyVaultKey> ImportKey(
ImportKeyOptions const& importKeyOptions,
Azure::Core::Context const& context = Azure::Core::Context()) const;
};
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -9,61 +9,29 @@
#pragma once
#include <azure/core/http/http.hpp>
#include <azure/core/internal/client_options.hpp>
#include <azure/core/response.hpp>
#include <azure/keyvault/common/client_options.hpp>
#include "azure/keyvault/keys/key_vault_key.hpp"
namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
/**
* @brief Available and supported service versions.
*
*/
enum class ServiceVersion
{
V7_0,
V7_1,
V7_2
};
/**
* @brief Define the options to create an SDK Keys client.
*
*/
struct KeyClientOptions : public Azure::Core::_internal::ClientOptions
struct KeyClientOptions : public Azure::Security::KeyVault::Common::ClientOptions
{
/**
* @brief The service version. All request are created with this version.
*
*/
ServiceVersion Version;
/**
* @brief Construct a new Key Client Options object.
*
* @param version Optional version for the client.
*/
KeyClientOptions(ServiceVersion version = ServiceVersion::V7_2)
: ClientOptions(), Version(version)
KeyClientOptions(
Azure::Security::KeyVault::Common::ServiceVersion version
= Azure::Security::KeyVault::Common::ServiceVersion::V7_2)
: ClientOptions(version)
{
}
std::string GetVersionString() const
{
switch (Version)
{
case ServiceVersion::V7_0:
return "7.0";
case ServiceVersion::V7_1:
return "7.1";
case ServiceVersion::V7_2:
return "7.2";
default:
throw std::runtime_error("Version not found");
}
}
};
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -53,7 +53,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
* Key Vault certificate, the value will be true.
*
*/
bool Managed;
bool Managed = false;
/**
* @brief Dictionary of tags with specific metadata about the key.

View File

@ -52,9 +52,10 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
OctHsm,
};
namespace _detail {
JsonWebKeyType KeyTypeFromString(std::string const& name);
std::string KeyTypeToString(JsonWebKeyType kty);
} // namespace _detail
struct KeyType
{
static JsonWebKeyType KeyTypeFromString(std::string const& name);
static std::string KeyTypeToString(JsonWebKeyType kty);
};
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -15,8 +15,8 @@
#include <azure/core/http/http.hpp>
#include <string>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
/**
@ -78,18 +78,4 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
*/
std::vector<KeyOperation> const& KeyOperations() const { return Key.KeyOperations(); }
};
/*********************** Deserializer / Serializer ******************************/
namespace _detail {
// Creates a new key based on a name and an http raw response.
KeyVaultKey KeyVaultKeyDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse);
// Updates a Key based on an Http raw response.
void KeyVaultKeyDeserialize(
KeyVaultKey& key,
Azure::Core::Http::RawResponse const& rawResponse);
} // namespace _detail
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Defines a page of listing keys from a Key Vault.
*
*/
#pragma once
#include "azure/keyvault/keys/deleted_key.hpp"
#include "azure/keyvault/keys/json_web_key.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
#include <azure/core/http/http.hpp>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
struct SinglePage
{
Azure::Nullable<std::string> ContinuationToken;
};
struct KeyPropertiesSinglePage : public SinglePage
{
std::vector<KeyProperties> Items;
};
struct DeletedKeySinglePage : public SinglePage
{
std::vector<DeletedKey> Items;
};
struct GetSinglePageOptions
{
Azure::Nullable<std::string> ContinuationToken;
Azure::Nullable<uint32_t> MaxResults;
};
struct GetPropertiesOfKeysSinglePageOptions : public GetSinglePageOptions
{
};
struct GetPropertiesOfKeyVersionsSinglePageOptions : public GetSinglePageOptions
{
};
struct GetDeletedKeysSinglePageOptions : public GetSinglePageOptions
{
};
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -0,0 +1,103 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief A long-running operation for recovering a Key.
*
*/
#pragma once
#include <azure/core/http/http.hpp>
#include <azure/core/operation.hpp>
#include <azure/core/operation_status.hpp>
#include <azure/core/response.hpp>
#include <azure/keyvault/common/internal/keyvault_pipeline.hpp>
#include <azure/keyvault/common/keyvault_exception.hpp>
#include "azure/keyvault/keys/key_vault_key.hpp"
#include <memory>
#include <string>
#include <thread>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
/**
* @brief A long running operation to recover a key.
*
*/
class RecoverDeletedKeyOperation : public Azure::Core::Operation<KeyVaultKey> {
private:
/* RecoverDeletedKeyOperation can be constructed only by friends classes (internal creation).
* The constructor is private and requires internal components.*/
friend class KeyClient;
std::shared_ptr<Azure::Security::KeyVault::Common::_internal::KeyVaultPipeline> m_pipeline;
Azure::Security::KeyVault::Keys::KeyVaultKey m_value;
std::string m_continuationToken;
std::unique_ptr<Azure::Core::Http::RawResponse> PollInternal(
Azure::Core::Context& context) override;
Azure::Response<Azure::Security::KeyVault::Keys::KeyVaultKey> PollUntilDoneInternal(
std::chrono::milliseconds period,
Azure::Core::Context& context) override
{
while (true)
{
// Poll will update the raw response.
Poll(context);
if (IsDone())
{
break;
}
std::this_thread::sleep_for(period);
}
return Azure::Response<Azure::Security::KeyVault::Keys::KeyVaultKey>(
m_value, std::make_unique<Azure::Core::Http::RawResponse>(*m_rawResponse));
}
/*
* Only friend classes are permitted to construct a RecoverDeletedKeyOperation. This is because
* a KeyVaultPipelne is required and it is not exposed to customers.
*
* Since C++ doesn't offer `internal` access, we use friends-only instead.
*/
RecoverDeletedKeyOperation(
std::shared_ptr<Azure::Security::KeyVault::Common::_internal::KeyVaultPipeline>
keyvaultPipeline,
Azure::Response<Azure::Security::KeyVault::Keys::KeyVaultKey> response);
/**
* @brief Get the #Azure::Core::Http::RawResponse of the operation request.
* @return A reference to an #Azure::Core::Http::RawResponse.
* @note Does not give up ownership of the RawResponse.
*/
Azure::Core::Http::RawResponse const& GetRawResponseInternal() const override
{
return *m_rawResponse;
}
public:
/**
* @brief Get the #Azure::Security::KeyVault::Keys::KeyVaultKey object.
*
* @remark The deleted key contains the recovery id if the key can be recovered.
*
* @return A deleted key object.
*/
Azure::Security::KeyVault::Keys::KeyVaultKey Value() const override { return m_value; }
/**
* @brief Get an Url as string which can be used to get the status of the delete key operation.
*
* @return std::string
*/
std::string GetResumeToken() const override { return m_continuationToken; }
};
}}}} // namespace Azure::Security::KeyVault::Keys

View File

@ -1,15 +0,0 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.13)
project (azure-security-keyvault-keys-sample-get-key LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable (
azure-security-keyvault-keys-sample-get-key
main.cpp
)
target_link_libraries(azure-security-keyvault-keys-sample-get-key PRIVATE azure-security-keyvault-keys azure-identity)

View File

@ -1,70 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @brief The next sample provides the code implementation to use the Key Vault SDK client for C++
* to create a key client and get a key from Key Vault service.
*
* @remark Make sure to set the next environment variables before running the sample.
* - AZURE_KEYVAULT_URL: To the KeyVault account url.
* - AZURE_KEYVAULT_TENANT_ID: Tenant id for the Azure account.
* - AZURE_KEYVAULT_CLIENT_ID: The client id to authenticate the request.
* - AZURE_KEYVAULT_CLIENT_SECRET: The secret id from the client id.
*
* Also, make sure the key is already created. Then set the key name as `KEY_VAULT_KEY_NAME` before
* the main() method below.
*
* @remark The sample has logging enabled and will log the HTTP response into the standard output.
*
*/
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <azure/core/http/http.hpp>
#include <azure/core/logging/logging.hpp>
#include <azure/identity/client_secret_credential.hpp>
#include <azure/keyvault/common/keyvault_exception.hpp>
#include <azure/keyvault/key_vault.hpp>
#include <iostream>
#include <memory>
using namespace Azure::Security::KeyVault::Keys;
// Define the name of the key to get
#define KEY_VAULT_KEY_NAME "keyName"
int main()
{
auto tenantId = std::getenv("AZURE_KEYVAULT_TENANT_ID");
auto clientId = std::getenv("AZURE_KEYVAULT_CLIENT_ID");
auto clientSecret = std::getenv("AZURE_KEYVAULT_CLIENT_SECRET");
auto credential
= std::make_shared<Azure::Identity::ClientSecretCredential>(tenantId, clientId, clientSecret);
KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
try
{
auto responseT = keyClient.GetKey(KEY_VAULT_KEY_NAME);
auto key = responseT.ExtractValue();
std::cout << "KeyId: " << key.Key.Id << std::endl;
std::cout << "Operations:" << std::endl;
for (KeyOperation operation : key.KeyOperations())
{
std::cout << " - " << operation.ToString() << std::endl;
}
}
catch (Azure::Core::Credentials::AuthenticationException const& e)
{
std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
}
catch (Azure::Security::KeyVault::Common::KeyVaultException const& e)
{
std::cout << "KeyVault Client Exception happened:" << std::endl << e.Message << std::endl;
}
return 0;
}

View File

@ -0,0 +1,19 @@
---
page_type: sample
languages:
- c++ 14
products:
- azure
- azure-key-vault
name: Azure Security KeyVault Keys samples for C++
description: Samples for the azure-security-keyVault-keys client library.
---
# Azure.Security.KeyVault.Keys Samples
- Creating, getting, updating, and deleting keys
- Back up and restore a key
- Listing keys, key versions, and deleted keys
- Encrypting and decrypt keys
- Signing and verifying keys
- Wrapping and unwrap a key

View File

@ -0,0 +1,101 @@
# Creating, getting, updating, and deleting keys
This sample demonstrates how to create, get, update, and delete a key in Azure Key Vault.
To get started, you'll need a URI to an Azure Key Vault. See the [README](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md) for links and instructions.
## Creating a KeyClient
To create a new `KeyClient` to create, get, update, or delete keys, you need the endpoint to an Azure Key Vault and credentials.
Key Vault Keys client for C++ currently supports the `ClientSecretCredential` for authenticating.
In the sample below, you can create a credential by setting the tenant id, client id and client secret as environment variables.
```cpp Snippet:KeysSample1CreateCredential
auto tenantId = std::getenv("AZURE_TENANT_ID");
auto clientId = std::getenv("AZURE_CLIENT_ID");
auto clientSecret = std::getenv("AZURE_CLIENT_SECRET");
auto credential = std::make_shared<Azure::Identity::ClientSecretCredential>(tenantId, clientId, clientSecret);
```
Then, in the sample below, you can set `keyVaultUrl` based on an environment variable, configuration setting, or any way that works for your application.
```cpp Snippet:KeysSample1KeyClient
KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
```
## Creating a key
Let's create an RSA key valid for 1 year.
If the key already exists in the Azure Key Vault, then a new version of the key is created.
```cpp Snippet:KeysSample1CreateKey
auto rsaKey = CreateRsaKeyOptions(rsaKeyName);
rsaKey.KeySize = 2048;
rsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
keyClient.CreateRsaKey(rsaKey);
```
## Getting a key
Let's get the cloud RSA key from the Azure Key Vault.
```cpp Snippet:KeysSample1GetKey
KeyVaultKey cloudRsaKey = keyClient.GetKey(rsaKeyName).ExtractValue();
std::cout << "Key is returned with name " << cloudRsaKey.Name() << " and type "
<< KeyType::KeyTypeToString(cloudRsaKey.GetKeyType()) << std::endl;
```
## Updating key properties
After one year, the cloud RSA key is still required, so we need to update the expiry time of the key.
The update method can be used to update the expiry attribute of the key.
```cpp Snippet:KeysSample1UpdateKeyProperties
cloudRsaKey.Properties.ExpiresOn
= cloudRsaKey.Properties.ExpiresOn.GetValue() + std::chrono::hours(24 * 365);
KeyVaultKey updatedKey = keyClient.UpdateKeyProperties(cloudRsaKey.Properties).ExtractValue();
std::cout << "Key's updated expiry time is " << updatedKey.Properties.ExpiresOn->ToString()
<< std::endl;
```
## Updating a key size
We need the cloud RSA key with bigger key size, so you want to update the key in Azure Key Vault to ensure it has the required size.
Calling `CreateRsaKey` on an existing key creates a new version of the key in the Azure Key Vault with the new specified size.
```cpp Snippet:KeysSample1UpdateKey
CreateRsaKeyOptions newRsaKey(rsaKeyName);
newRsaKey.KeySize = 4096;
newRsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
keyClient.CreateRsaKey(newRsaKey);
```
## Deleting a key
The cloud RSA key is no longer needed, so we need to delete it from the Key Vault.
```cpp Snippet:KeysSample1DeleteKey
DeleteKeyOperation operation = keyClient.StartDeleteKey(rsaKeyName);
```
## Purging a deleted key
If the Azure Key Vault is soft delete-enabled and you want to permanently delete the key before its `ScheduledPurgeDate`,
the deleted key needs to be purged. Before it can be purged, you need to wait until the key is fully deleted.
```cpp Snippet:KeysSample1PurgeKey
// You only need to wait for completion if you want to purge or recover the key.
operation.PollUntilDone(std::chrono::milliseconds(2000));
keyClient.PurgeDeletedKey(rsaKeyName);
```
## Source
- sample1_hello_world.cpp
[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md

View File

@ -0,0 +1,64 @@
# Back up and restore a key
This sample demonstrates how to back up and restore a Key from Azure Key Vault.
To get started, you'll need a URI to an Azure Key Vault. See the [README](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md) for links and instructions.
## Creating a KeyClient
To create a new `KeyClient` to create, get, update, or delete keys, you need the endpoint to an Azure Key Vault and credentials.
Key Vault Keys client for C++ currently supports the `ClientSecretCredential` for authenticating.
In the sample below, you can create a credential by setting the tenant id, client id and client secret as environment variables.
```cpp Snippet:KeysSample1CreateCredential
auto tenantId = std::getenv("AZURE_TENANT_ID");
auto clientId = std::getenv("AZURE_CLIENT_ID");
auto clientSecret = std::getenv("AZURE_CLIENT_SECRET");
auto credential = std::make_shared<Azure::Identity::ClientSecretCredential>(tenantId, clientId, clientSecret);
```
Then, in the sample below, you can set `keyVaultUrl` based on an environment variable, configuration setting, or any way that works for your application.
```cpp Snippet:KeysSample1KeyClient
KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
```
## Creating a key
Let's create an RSA key valid for 1 year.
If the key already exists in the Azure Key Vault, then a new version of the key is created.
```cpp Snippet:KeysSample1CreateKey
auto rsaKey = CreateRsaKeyOptions(rsaKeyName);
rsaKey.KeySize = 2048;
rsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
keyClient.CreateRsaKey(rsaKey);
```
## Backing up a key
You might make backups in case keys get accidentally deleted.
For long term storage, it is ideal to write the backup to a file, disk, database, etc.
For the purposes of this sample, we are storing the back up in a temporary memory area.
```cpp Snippet:KeysSample2BackupKey
std::vector<uint8_t> backupKey(keyClient.BackupKey(rsaKeyName).ExtractValue());
```
## Restoring a key
If the key is deleted for any reason, we can use the backup value to restore it in the Azure Key Vault.
```cpp Snippet:KeysSample2RestoreKey
auto restoredKey = keyClient.RestoreKeyBackup(inMemoryBackup).ExtractValue();
```
## Source
To see the full example source, see:
- sample2_backup_and_restore.cpp
[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md

View File

@ -0,0 +1,171 @@
# Listing keys, key versions, and deleted keys
This sample demonstrates how to list keys and versions of a given key, and list deleted keys in a soft delete-enabled Key Vault.
To get started, you'll need a URI to an Azure Key Vault. See the [README](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/keyvault/Azure.Security.KeyVault.Keys/README.md) for links and instructions.
## Creating a KeyClient
To create a new `KeyClient` to create, get, update, or delete keys, you need the endpoint to an Azure Key Vault and credentials.
Key Vault Keys client for C++ currently supports the `ClientSecretCredential` for authenticating.
In the sample below, you can create a credential by setting the tenant id, client id and client secret as environment variables.
```cpp Snippet:KeysSample1CreateCredential
auto tenantId = std::getenv("AZURE_TENANT_ID");
auto clientId = std::getenv("AZURE_CLIENT_ID");
auto clientSecret = std::getenv("AZURE_CLIENT_SECRET");
auto credential = std::make_shared<Azure::Identity::ClientSecretCredential>(tenantId, clientId, clientSecret);
```
Then, in the sample below, you can set `keyVaultUrl` based on an environment variable, configuration setting, or any way that works for your application.
```cpp Snippet:KeysSample1KeyClient
KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
```
## Creating a key
Let's create an RSA key valid for 1 year.
If the key already exists in the Azure Key Vault, then a new version of the key is created.
```cpp Snippet:KeysSample1CreateKey
std::string rsaKeyName("CloudRsaKey-" + Azure::Core::Uuid::CreateUuid().ToString());
auto rsaKey = CreateRsaKeyOptions(rsaKeyName);
rsaKey.KeySize = 2048;
rsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
std::string ecKeyName("CloudEcKey-" + Azure::Core::Uuid::CreateUuid().ToString());
auto ecKey = CreateEcKeyOptions(ecKeyName);
ecKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
std::cout << "\t-Create Keys" << std::endl;
keyClient.CreateRsaKey(rsaKey);
keyClient.CreateEcKey(ecKey);
```
## Listing keys
You need to check the type of keys that already exist in your Azure Key Vault.
Let's list the keys and print their types. List operations don't return the actual key, but only properties of the key.
So, for each returned key we call GetKey to get the actual key.
```cpp Snippet:KeysSample3ListKeys
for (auto keysSinglePage = keyClient.GetPropertiesOfKeysSinglePage().ExtractValue();;)
{
for (auto const& key : keysSinglePage.Items)
{
if (key.Managed)
{
continue;
}
auto keyWithType = keyClient.GetKey(key.Name).ExtractValue();
std::cout << "Key is returned with name: " << keyWithType.Name()
<< " and type: " << KeyType::KeyTypeToString(keyWithType.GetKeyType())
<< std::endl;
}
if (!keysSinglePage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetPropertiesOfKeysSinglePageOptions options;
options.ContinuationToken = keysSinglePage.ContinuationToken.GetValue();
keysSinglePage = keyClient.GetPropertiesOfKeysSinglePage(options).ExtractValue();
}
```
## Updating RSA key size
We need the cloud RSA key with bigger key size, so you want to update the key in Azure Key Vault to ensure it has the required size.
Calling `CreateRsaKey` on an existing key creates a new version of the key in the Azure Key Vault with the new specified size.
```cpp Snippet:KeysSample3UpdateKey
CreateRsaKeyOptions newRsaKey(rsaKeyName);
newRsaKey.KeySize = 4096;
newRsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
keyClient.CreateRsaKey(newRsaKey);
```
## Listing key versions
You need to check all the different versions cloud RSA key had previously.
Lets print all the versions of this key.
```cpp Snippet:KeysSample3ListKeyVersions
for (auto keyVersionsSinglePage
= keyClient.GetPropertiesOfKeyVersionsSinglePage(rsaKeyName).ExtractValue();
;)
{
for (auto const& key : keyVersionsSinglePage.Items)
{
std::cout << "Key's version: " << key.Version << " with name: " << key.Name << std::endl;
}
if (!keyVersionsSinglePage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetPropertiesOfKeyVersionsSinglePageOptions options;
options.ContinuationToken = keyVersionsSinglePage.ContinuationToken.GetValue();
keyVersionsSinglePage
= keyClient.GetPropertiesOfKeyVersionsSinglePage(rsaKeyName, options).ExtractValue();
}
```
## Deleting keys
The cloud RSA Key and the cloud EC keys are no longer needed.
You need to delete them from the Azure Key Vault.
```cpp Snippet:KeysSample3DeletedKeys
DeleteKeyOperation rsaOperation = keyClient.StartDeleteKey(rsaKeyName);
DeleteKeyOperation ecOperation = keyClient.StartDeleteKey(ecKeyName);
// You only need to wait for completion if you want to purge or recover the key.
rsaOperation.PollUntilDone(std::chrono::milliseconds(2000));
ecOperation.PollUntilDone(std::chrono::milliseconds(2000));
```
## Listing deleted keys
You can list all the deleted and non-purged keys, assuming Azure Key Vault is soft delete-enabled.
```cpp Snippet:KeysSample3ListDeletedKeys
nextPage = true;
for (auto keysDeletedPage = keyClient.GetDeletedKeysSinglePage().ExtractValue();;)
{
for (auto const& key : keysDeletedPage.Items)
{
std::cout << "Deleted key's name: " << key.Name()
<< ", recovery level: " << key.Properties.RecoveryLevel
<< " and recovery Id: " << key.RecoveryId << std::endl;
}
if (!keysDeletedPage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetDeletedKeysSinglePageOptions options;
options.ContinuationToken = keysDeletedPage.ContinuationToken.GetValue();
keysDeletedPage = keyClient.GetDeletedKeysSinglePage(options).ExtractValue();
}
```
## Source
To see the full example source, see:
- sample3_get_keys.cpp
[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/README.md

View File

@ -3,6 +3,7 @@
#include "azure/keyvault/keys/delete_key_operation.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
using namespace Azure::Security::KeyVault::Keys;
@ -38,7 +39,7 @@ Azure::Security::KeyVault::Keys::DeleteKeyOperation::PollInternal(Azure::Core::C
m_status = CheckCompleted(*rawResponse);
if (m_status == Azure::Core::OperationStatus::Succeeded)
{
m_value = _detail::DeletedKeyDeserialize(m_value.Name(), *rawResponse);
m_value = _detail::DeletedKeySerializer::DeletedKeyDeserialize(m_value.Name(), *rawResponse);
}
}

View File

@ -1,18 +1,21 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "azure/keyvault/keys/deleted_key.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
#include <azure/core/internal/json/json.hpp>
#include <azure/core/internal/json/json_optional.hpp>
#include <azure/keyvault/common/internal/unix_time_helper.hpp>
#include <azure/core/internal/json/json.hpp>
#include "azure/keyvault/keys/deleted_key.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Core::Json::_internal;
using Azure::Security::KeyVault::Common::_internal::UnixTimeConverter;
DeletedKey _detail::DeletedKeyDeserialize(
DeletedKey _detail::DeletedKeySerializer::DeletedKeyDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse)
{
@ -21,16 +24,30 @@ DeletedKey _detail::DeletedKeyDeserialize(
// "Key"
DeletedKey deletedKey(name);
_detail::KeyVaultKeyDeserialize(deletedKey, rawResponse);
_detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(deletedKey, rawResponse);
// recoveryId
// deletedDate
// scheduledPurgeDate
deletedKey.RecoveryId = jsonParser[_detail::RecoveryIdPropertyName].get<std::string>();
deletedKey.DeletedDate = UnixTimeConverter::UnixTimeToDatetime(
jsonParser[_detail::DeletedOnPropertyName].get<uint64_t>());
deletedKey.ScheduledPurgeDate = UnixTimeConverter::UnixTimeToDatetime(
jsonParser[_detail::ScheduledPurgeDatePropertyName].get<uint64_t>());
if (!jsonParser[_detail::RecoveryIdPropertyName].is_null())
{
deletedKey.RecoveryId = jsonParser[_detail::RecoveryIdPropertyName].get<std::string>();
}
if (!jsonParser[_detail::RecoveryLevelPropertyName].is_null())
{
deletedKey.Properties.RecoveryLevel
= jsonParser[_detail::RecoveryLevelPropertyName].get<std::string>();
}
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
deletedKey.DeletedDate,
jsonParser,
_detail::DeletedOnPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
deletedKey.ScheduledPurgeDate,
jsonParser,
_detail::ScheduledPurgeDatePropertyName,
UnixTimeConverter::UnixTimeToDatetime);
return deletedKey;
}

View File

@ -0,0 +1,73 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include <azure/core/internal/json/json.hpp>
#include <azure/core/internal/json/json_optional.hpp>
#include <azure/keyvault/common/internal/unix_time_helper.hpp>
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
#include "azure/keyvault/keys/import_key_options.hpp"
#include <string>
using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Security::KeyVault::Keys::_detail;
using namespace Azure::Core::Json::_internal;
using namespace Azure::Security::KeyVault::Common::_internal;
std::string
Azure::Security::KeyVault::Keys::_detail::ImportKeyOptionsSerializer::ImportKeyOptionsSerialize(
ImportKeyOptions const& importKeyOptions)
{
Azure::Core::Json::_internal::json payload;
// key
payload[_detail::KeyPropertyName] = importKeyOptions.Key;
// hsm
SetFromNullable(importKeyOptions.HardwareProtected, payload, _detail::HsmPropertyName);
// attributes
SetFromNullable<Azure::DateTime, uint64_t>(
importKeyOptions.Properties.CreatedOn,
payload[_detail::AttributesPropertyName],
_detail::CreatedPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
SetFromNullable(
importKeyOptions.Properties.Enabled,
payload[_detail::AttributesPropertyName],
_detail::EnabledPropertyName);
SetFromNullable<Azure::DateTime, uint64_t>(
importKeyOptions.Properties.ExpiresOn,
payload[_detail::AttributesPropertyName],
_detail::ExpPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
SetFromNullable<Azure::DateTime, uint64_t>(
importKeyOptions.Properties.NotBefore,
payload[_detail::AttributesPropertyName],
_detail::NbfPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
SetFromNullable(
importKeyOptions.Properties.RecoverableDays,
payload[_detail::AttributesPropertyName],
_detail::RecoverableDaysPropertyName);
payload[_detail::RecoveryLevelPropertyName] = importKeyOptions.Properties.RecoveryLevel;
SetFromNullable<Azure::DateTime, uint64_t>(
importKeyOptions.Properties.UpdatedOn,
payload[_detail::AttributesPropertyName],
_detail::UpdatedPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
// tags
for (auto& tag : importKeyOptions.Properties.Tags)
{
payload[_detail::TagsPropertyName][tag.first] = tag.second;
}
// release_policy
return payload.dump();
}

View File

@ -0,0 +1,28 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include <azure/keyvault/common/internal/base64url.hpp>
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/json_web_key.hpp"
#include <string>
using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Core::Json::_internal;
using namespace Azure::Security::KeyVault::Common::_internal;
void Azure::Security::KeyVault::Keys::to_json(
Azure::Core::Json::_internal::json& j,
JsonWebKey const& p)
{
j[_detail::KeyTypePropertyName] = KeyType::KeyTypeToString(p.KeyType);
j[_detail::NPropertyName] = Base64Url::Base64UrlEncode(p.N);
j[_detail::EPropertyName] = Base64Url::Base64UrlEncode(p.E);
j[_detail::DPropertyName] = Base64Url::Base64UrlEncode(p.D);
j[_detail::DPPropertyName] = Base64Url::Base64UrlEncode(p.DP);
j[_detail::DQPropertyName] = Base64Url::Base64UrlEncode(p.DQ);
j[_detail::QIPropertyName] = Base64Url::Base64UrlEncode(p.QI);
j[_detail::PPropertyName] = Base64Url::Base64UrlEncode(p.P);
j[_detail::QPropertyName] = Base64Url::Base64UrlEncode(p.Q);
}

View File

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include <azure/core/internal/json/json.hpp>
#include <azure/core/internal/json/json_optional.hpp>
#include <azure/keyvault/common/internal/base64url.hpp>
#include "azure/keyvault/keys/details/key_backup.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include <string>
using namespace Azure::Security::KeyVault::Keys::_detail;
using namespace Azure::Core::Json::_internal;
using namespace Azure::Security::KeyVault::Common::_internal;
std::string KeyBackup::Serialize() const
{
Azure::Core::Json::_internal::json payload;
payload["value"] = Base64Url::Base64UrlEncode(Value);
// release_policy
return payload.dump();
}
KeyBackup KeyBackup::Deserialize(Azure::Core::Http::RawResponse const& rawResponse)
{
auto const& body = rawResponse.GetBody();
auto jsonParser = json::parse(body);
KeyBackup keyBackup;
JsonOptional::SetIfExists<std::string, std::vector<uint8_t>>(
keyBackup.Value, jsonParser, "value", [](std::string const& value) {
return Base64Url::Base64UrlDecode(value);
});
return keyBackup;
}

View File

@ -5,8 +5,10 @@
#include <azure/core/http/http.hpp>
#include <azure/core/http/policies/policy.hpp>
#include "azure/keyvault/keys/details/key_backup.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_request_parameters.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
#include "azure/keyvault/keys/key_client.hpp"
#include <memory>
@ -17,6 +19,41 @@ using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Core::Http;
using namespace Azure::Core::Http::Policies;
namespace {
struct RequestWithContinuationToken
{
std::vector<std::string> Path;
std::unique_ptr<std::map<std::string, std::string>> Query;
};
static inline RequestWithContinuationToken BuildRequestFromContinuationToken(
GetSinglePageOptions const& options,
std::vector<std::string>&& defaultPath)
{
RequestWithContinuationToken request;
request.Path = defaultPath;
if (options.ContinuationToken)
{
// 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(options.ContinuationToken.GetValue());
request.Query
= std::make_unique<std::map<std::string, std::string>>(nextPageUrl.GetQueryParameters());
request.Path.clear();
request.Path.emplace_back(nextPageUrl.GetPath());
}
if (options.MaxResults)
{
if (request.Query == nullptr)
{
request.Query = std::make_unique<std::map<std::string, std::string>>();
}
request.Query->emplace("maxResults", std::to_string(options.MaxResults.GetValue()));
}
return request;
}
} // namespace
KeyClient::KeyClient(
std::string const& vaultUrl,
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
@ -49,7 +86,7 @@ Azure::Response<KeyVaultKey> KeyClient::GetKey(
context,
Azure::Core::Http::HttpMethod::Get,
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeyDeserialize(name, rawResponse);
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(name, rawResponse);
},
{_detail::KeysPath, name, options.Version});
}
@ -65,7 +102,7 @@ Azure::Response<KeyVaultKey> KeyClient::CreateKey(
Azure::Core::Http::HttpMethod::Post,
_detail::KeyRequestParameters(keyType, options),
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeyDeserialize(name, rawResponse);
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(name, rawResponse);
},
{_detail::KeysPath, name, "create"});
}
@ -80,7 +117,7 @@ Azure::Response<KeyVaultKey> KeyClient::CreateEcKey(
Azure::Core::Http::HttpMethod::Post,
_detail::KeyRequestParameters(ecKeyOptions),
[&keyName](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeyDeserialize(keyName, rawResponse);
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(keyName, rawResponse);
},
{_detail::KeysPath, keyName, "create"});
}
@ -95,7 +132,7 @@ Azure::Response<KeyVaultKey> KeyClient::CreateRsaKey(
Azure::Core::Http::HttpMethod::Post,
_detail::KeyRequestParameters(rsaKeyOptions),
[&keyName](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeyDeserialize(keyName, rawResponse);
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(keyName, rawResponse);
},
{_detail::KeysPath, keyName, "create"});
}
@ -110,11 +147,45 @@ Azure::Response<KeyVaultKey> KeyClient::CreateOctKey(
Azure::Core::Http::HttpMethod::Post,
_detail::KeyRequestParameters(octKeyOptions),
[&keyName](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeyDeserialize(keyName, rawResponse);
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(keyName, rawResponse);
},
{_detail::KeysPath, keyName, "create"});
}
Azure::Response<KeyPropertiesSinglePage> KeyClient::GetPropertiesOfKeysSinglePage(
GetPropertiesOfKeysSinglePageOptions const& options,
Azure::Core::Context const& context) const
{
auto const request = BuildRequestFromContinuationToken(options, {_detail::KeysPath});
return m_pipeline->SendRequest<KeyPropertiesSinglePage>(
context,
Azure::Core::Http::HttpMethod::Get,
[](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyPropertiesSinglePageSerializer::KeyPropertiesSinglePageDeserialize(
rawResponse);
},
request.Path,
request.Query);
}
Azure::Response<KeyPropertiesSinglePage> KeyClient::GetPropertiesOfKeyVersionsSinglePage(
std::string const& name,
GetPropertiesOfKeyVersionsSinglePageOptions const& options,
Azure::Core::Context const& context) const
{
auto const request
= BuildRequestFromContinuationToken(options, {_detail::KeysPath, name, "versions"});
return m_pipeline->SendRequest<KeyPropertiesSinglePage>(
context,
Azure::Core::Http::HttpMethod::Get,
[](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyPropertiesSinglePageSerializer::KeyPropertiesSinglePageDeserialize(
rawResponse);
},
request.Path,
request.Query);
}
Azure::Security::KeyVault::Keys::DeleteKeyOperation KeyClient::StartDeleteKey(
std::string const& name,
Azure::Core::Context const& context) const
@ -125,11 +196,26 @@ Azure::Security::KeyVault::Keys::DeleteKeyOperation KeyClient::StartDeleteKey(
context,
Azure::Core::Http::HttpMethod::Delete,
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::DeletedKeyDeserialize(name, rawResponse);
return _detail::DeletedKeySerializer::DeletedKeyDeserialize(name, rawResponse);
},
{_detail::KeysPath, name}));
}
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation KeyClient::StartRecoverDeletedKey(
std::string const& name,
Azure::Core::Context const& context) const
{
return Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation(
m_pipeline,
m_pipeline->SendRequest<Azure::Security::KeyVault::Keys::KeyVaultKey>(
context,
Azure::Core::Http::HttpMethod::Post,
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(name, rawResponse);
},
{_detail::DeletedKeysPath, name, "recover"}));
}
Azure::Response<DeletedKey> KeyClient::GetDeletedKey(
std::string const& name,
Azure::Core::Context const& context) const
@ -138,7 +224,118 @@ Azure::Response<DeletedKey> KeyClient::GetDeletedKey(
context,
Azure::Core::Http::HttpMethod::Get,
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::DeletedKeyDeserialize(name, rawResponse);
return _detail::DeletedKeySerializer::DeletedKeyDeserialize(name, rawResponse);
},
{_detail::DeletedKeysPath, name});
}
Azure::Response<DeletedKeySinglePage> KeyClient::GetDeletedKeysSinglePage(
GetDeletedKeysSinglePageOptions const& options,
Azure::Core::Context const& context) const
{
auto const request = BuildRequestFromContinuationToken(options, {_detail::DeletedKeysPath});
return m_pipeline->SendRequest<DeletedKeySinglePage>(
context,
Azure::Core::Http::HttpMethod::Get,
[](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyPropertiesSinglePageSerializer::DeletedKeySinglePageDeserialize(
rawResponse);
},
request.Path,
request.Query);
}
Azure::Response<PurgedKey> KeyClient::PurgeDeletedKey(
std::string const& name,
Azure::Core::Context const& context) const
{
return m_pipeline->SendRequest<PurgedKey>(
context,
Azure::Core::Http::HttpMethod::Delete,
[](Azure::Core::Http::RawResponse const&) { return PurgedKey(); },
{_detail::DeletedKeysPath, name});
}
Azure::Response<KeyVaultKey> KeyClient::UpdateKeyProperties(
KeyProperties const& properties,
Azure::Nullable<std::list<KeyOperation>> const& keyOperations,
Azure::Core::Context const& context) const
{
return m_pipeline->SendRequest<KeyVaultKey>(
context,
Azure::Core::Http::HttpMethod::Patch,
_detail::KeyRequestParameters(properties, keyOperations),
[&properties](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(properties.Name, rawResponse);
},
{_detail::KeysPath, properties.Name, properties.Version});
}
Azure::Response<std::vector<uint8_t>> KeyClient::BackupKey(
std::string const& name,
Azure::Core::Context const& context) const
{
// Use the internal model KeyBackup to parse from Json
auto response = m_pipeline->SendRequest<_detail::KeyBackup>(
context,
Azure::Core::Http::HttpMethod::Post,
[](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyBackup::Deserialize(rawResponse);
},
{_detail::KeysPath, name, "backup"});
// Convert the internal KeyBackup model to a raw vector<uint8_t>.
return Azure::Response<std::vector<uint8_t>>(
response.ExtractValue().Value, response.ExtractRawResponse());
}
Azure::Response<KeyVaultKey> KeyClient::RestoreKeyBackup(
std::vector<uint8_t> const& backup,
Azure::Core::Context const& context) const
{
_detail::KeyBackup backupModel;
backupModel.Value = backup;
return m_pipeline->SendRequest<KeyVaultKey>(
context,
Azure::Core::Http::HttpMethod::Post,
backupModel,
[](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(rawResponse);
},
{_detail::KeysPath, "restore"});
}
Azure::Response<KeyVaultKey> KeyClient::ImportKey(
std::string const& name,
JsonWebKey const& keyMaterial,
Azure::Core::Context const& context) const
{
ImportKeyOptions const importKeyOptions(name, keyMaterial);
return m_pipeline->SendRequest<KeyVaultKey>(
context,
Azure::Core::Http::HttpMethod::Put,
[&importKeyOptions]() {
return _detail::ImportKeyOptionsSerializer::ImportKeyOptionsSerialize(importKeyOptions);
},
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(name, rawResponse);
},
{_detail::KeysPath, name});
}
Azure::Response<KeyVaultKey> KeyClient::ImportKey(
ImportKeyOptions const& importKeyOptions,
Azure::Core::Context const& context) const
{
return m_pipeline->SendRequest<KeyVaultKey>(
context,
Azure::Core::Http::HttpMethod::Put,
[&importKeyOptions]() {
return _detail::ImportKeyOptionsSerializer::ImportKeyOptionsSerialize(importKeyOptions);
},
[&importKeyOptions](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(
importKeyOptions.Name(), rawResponse);
},
{_detail::KeysPath, importKeyOptions.Name()});
}

View File

@ -2,6 +2,9 @@
// SPDX-License-Identifier: MIT
#include <azure/core/internal/json/json.hpp>
#include <azure/core/internal/json/json_optional.hpp>
#include <azure/keyvault/common/internal/unix_time_helper.hpp>
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_request_parameters.hpp"
@ -9,14 +12,22 @@
#include <string>
using namespace Azure::Security::KeyVault::Keys::_detail;
using namespace Azure::Core::Json::_internal;
using namespace Azure::Security::KeyVault::Common::_internal;
std::string KeyRequestParameters::Serialize() const
{
Azure::Core::Json::_internal::json payload;
/* Mandatory */
// kty
payload[_detail::KeyTypePropertyName] = KeyTypeToString(m_keyType);
SetFromNullable<JsonWebKeyType, std::string>(
m_keyType, payload, _detail::KeyTypePropertyName, [](JsonWebKeyType type) {
return KeyType::KeyTypeToString(type);
});
// attributes
SetFromNullable(
m_options.Enabled, payload[_detail::AttributesPropertyName], _detail::EnabledPropertyName);
/* Optional */
// key_size
@ -28,6 +39,18 @@ std::string KeyRequestParameters::Serialize() const
}
// attributes
SetFromNullable<Azure::DateTime, uint64_t>(
m_options.ExpiresOn,
payload[_detail::AttributesPropertyName],
_detail::ExpPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
SetFromNullable<Azure::DateTime, uint64_t>(
m_options.NotBefore,
payload[_detail::AttributesPropertyName],
_detail::NbfPropertyName,
UnixTimeConverter::DatetimeToUnixTime);
// tags
for (auto tag : m_options.Tags)
{

View File

@ -8,60 +8,60 @@
using namespace Azure::Security::KeyVault::Keys;
JsonWebKeyType _detail::KeyTypeFromString(std::string const& name)
JsonWebKeyType KeyType::KeyTypeFromString(std::string const& name)
{
if (name == EcValue)
if (name == _detail::EcValue)
{
return JsonWebKeyType::Ec;
}
if (name == EcHsmValue)
if (name == _detail::EcHsmValue)
{
return JsonWebKeyType::EcHsm;
}
if (name == OctValue)
if (name == _detail::OctValue)
{
return JsonWebKeyType::Oct;
}
if (name == OctHsmValue)
if (name == _detail::OctHsmValue)
{
return JsonWebKeyType::OctHsm;
}
if (name == RsaValue)
if (name == _detail::RsaValue)
{
return JsonWebKeyType::Rsa;
}
if (name == RsaHsmValue)
if (name == _detail::RsaHsmValue)
{
return JsonWebKeyType::RsaHsm;
}
throw std::runtime_error("cannot convert " + name + " to key type (kty)");
}
std::string _detail::KeyTypeToString(JsonWebKeyType kty)
std::string KeyType::KeyTypeToString(JsonWebKeyType kty)
{
if (kty == JsonWebKeyType::Ec)
{
return EcValue;
return _detail::EcValue;
}
if (kty == JsonWebKeyType::EcHsm)
{
return EcHsmValue;
return _detail::EcHsmValue;
}
if (kty == JsonWebKeyType::Oct)
{
return OctValue;
return _detail::OctValue;
}
if (kty == JsonWebKeyType::OctHsm)
{
return OctHsmValue;
return _detail::OctHsmValue;
}
if (kty == JsonWebKeyType::Rsa)
{
return RsaValue;
return _detail::RsaValue;
}
if (kty == JsonWebKeyType::RsaHsm)
{
return RsaHsmValue;
return _detail::RsaHsmValue;
}
return std::string();
}

View File

@ -1,15 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "azure/keyvault/keys/key_vault_key.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/key_curve_name.hpp"
#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>
#include <azure/core/url.hpp>
#include <azure/keyvault/common/internal/unix_time_helper.hpp>
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
#include "azure/keyvault/keys/key_curve_name.hpp"
#include "azure/keyvault/keys/key_vault_key.hpp"
using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Core::Json::_internal;
@ -27,22 +29,36 @@ void ParseStringOperationsToKeyOperations(
}
} // namespace
KeyVaultKey _detail::KeyVaultKeyDeserialize(
KeyVaultKey _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse)
{
KeyVaultKey key(name);
_detail::KeyVaultKeyDeserialize(key, rawResponse);
_detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(key, rawResponse);
return key;
}
void _detail::KeyVaultKeyDeserialize(
KeyVaultKey _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(
Azure::Core::Http::RawResponse const& rawResponse)
{
KeyVaultKey key;
_detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(key, rawResponse);
return key;
}
void _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(
KeyVaultKey& key,
Azure::Core::Http::RawResponse const& rawResponse)
{
auto body = rawResponse.GetBody();
auto const& body = rawResponse.GetBody();
auto jsonParser = json::parse(body);
_detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(key, jsonParser);
}
void _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(
KeyVaultKey& key,
Azure::Core::Json::_internal::json const& jsonParser)
{
// "Key"
if (jsonParser.contains(_detail::KeyPropertyName))
{
@ -57,7 +73,7 @@ void _detail::KeyVaultKeyDeserialize(
}
key.Key.Id = jsonKey[_detail::KeyIdPropertyName].get<std::string>();
key.Key.KeyType
= _detail::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get<std::string>());
= KeyType::KeyTypeFromString(jsonKey[_detail::KeyTypePropertyName].get<std::string>());
JsonOptional::SetIfExists<std::string, KeyCurveName>(
key.Key.CurveName, jsonKey, _detail::CurveNamePropertyName, [](std::string const& keyName) {
@ -65,20 +81,36 @@ void _detail::KeyVaultKeyDeserialize(
});
}
// Parse URL for the vaultUri, keyVersion
_detail::KeyVaultKeySerializer::ParseKeyUrl(key.Properties, key.Key.Id);
// "Attributes"
if (jsonParser.contains(_detail::AttributesPropertyName))
{
auto attributes = jsonParser[_detail::AttributesPropertyName];
JsonOptional::SetIfExists(key.Properties.Enabled, attributes, "enabled");
JsonOptional::SetIfExists(key.Properties.Enabled, attributes, _detail::EnabledPropertyName);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
key.Properties.NotBefore, attributes, "nbf", UnixTimeConverter::UnixTimeToDatetime);
key.Properties.NotBefore,
attributes,
_detail::NbfPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
key.Properties.ExpiresOn, attributes, "exp", UnixTimeConverter::UnixTimeToDatetime);
key.Properties.ExpiresOn,
attributes,
_detail::ExpPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
key.Properties.CreatedOn, attributes, "created", UnixTimeConverter::UnixTimeToDatetime);
key.Properties.CreatedOn,
attributes,
_detail::CreatedPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
key.Properties.UpdatedOn, attributes, "updated", UnixTimeConverter::UnixTimeToDatetime);
key.Properties.UpdatedOn,
attributes,
_detail::UpdatedPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
}
// "Tags"

View File

@ -0,0 +1,127 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "azure/keyvault/keys/list_keys_single_page_result.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
#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>
#include <azure/core/url.hpp>
using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Core::Json::_internal;
using Azure::Security::KeyVault::Common::_internal::UnixTimeConverter;
KeyPropertiesSinglePage
_detail::KeyPropertiesSinglePageSerializer::KeyPropertiesSinglePageDeserialize(
Azure::Core::Http::RawResponse const& rawResponse)
{
KeyPropertiesSinglePage result;
auto const& body = rawResponse.GetBody();
auto jsonParser = json::parse(body);
JsonOptional::SetIfExists(result.ContinuationToken, jsonParser, "nextLink");
// Key properties
auto keyPropertiesJson = jsonParser["value"];
for (auto const& key : keyPropertiesJson)
{
KeyProperties keyProperties;
keyProperties.Id = key[_detail::KeyIdPropertyName].get<std::string>();
_detail::KeyVaultKeySerializer::ParseKeyUrl(keyProperties, keyProperties.Id);
// "Attributes"
if (key.contains(_detail::AttributesPropertyName))
{
auto attributes = key[_detail::AttributesPropertyName];
JsonOptional::SetIfExists(keyProperties.Enabled, attributes, _detail::EnabledPropertyName);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
keyProperties.NotBefore,
attributes,
_detail::NbfPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
keyProperties.ExpiresOn,
attributes,
_detail::ExpPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
keyProperties.CreatedOn,
attributes,
_detail::CreatedPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
keyProperties.UpdatedOn,
attributes,
_detail::UpdatedPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
}
// "Tags"
if (key.contains(_detail::TagsPropertyName))
{
auto const& tags = key[_detail::TagsPropertyName];
for (auto tag = tags.begin(); tag != tags.end(); ++tag)
{
keyProperties.Tags.emplace(tag.key(), tag.value().get<std::string>());
}
}
// managed
if (key.contains(_detail::ManagedPropertyName))
{
keyProperties.Managed = key[_detail::ManagedPropertyName].get<bool>();
}
result.Items.emplace_back(keyProperties);
}
return result;
}
DeletedKeySinglePage _detail::KeyPropertiesSinglePageSerializer::DeletedKeySinglePageDeserialize(
Azure::Core::Http::RawResponse const& rawResponse)
{
auto const& body = rawResponse.GetBody();
auto jsonParser = Azure::Core::Json::_internal::json::parse(body);
DeletedKeySinglePage deletedKeySinglePage;
JsonOptional::SetIfExists(deletedKeySinglePage.ContinuationToken, jsonParser, "nextLink");
auto deletedKeys = jsonParser["value"];
for (auto const& key : deletedKeys)
{
DeletedKey deletedKey;
deletedKey.Properties.Id = key[_detail::KeyIdPropertyName].get<std::string>();
_detail::KeyVaultKeySerializer::ParseKeyUrl(deletedKey.Properties, deletedKey.Properties.Id);
if (!key[_detail::RecoveryIdPropertyName].is_null())
{
deletedKey.RecoveryId = key[_detail::RecoveryIdPropertyName].get<std::string>();
}
if (!key[_detail::AttributesPropertyName][_detail::RecoveryLevelPropertyName].is_null())
{
deletedKey.Properties.RecoveryLevel
= key[_detail::AttributesPropertyName][_detail::RecoveryLevelPropertyName]
.get<std::string>();
}
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
deletedKey.DeletedDate,
key,
_detail::DeletedOnPropertyName,
UnixTimeConverter::UnixTimeToDatetime);
JsonOptional::SetIfExists<uint64_t, Azure::DateTime>(
deletedKey.ScheduledPurgeDate,
key,
_detail::ScheduledPurgeDatePropertyName,
UnixTimeConverter::UnixTimeToDatetime);
deletedKeySinglePage.Items.emplace_back(deletedKey);
}
return deletedKeySinglePage;
}

View File

@ -0,0 +1,78 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "azure/keyvault/keys/recover_deleted_key_operation.hpp"
#include "azure/keyvault/keys/details/key_constants.hpp"
#include "azure/keyvault/keys/details/key_serializers.hpp"
using namespace Azure::Security::KeyVault::Keys;
namespace {
// For delete key, the LRO ends when we can retreive the Key from the deleted keys list from the
// server.
inline Azure::Core::OperationStatus CheckCompleted(Azure::Core::Http::RawResponse const& response)
{
auto const code = response.GetStatusCode();
switch (code)
{
case Azure::Core::Http::HttpStatusCode::Ok:
// Access denied but proof the key was deleted.
case Azure::Core::Http::HttpStatusCode::Forbidden:
return Azure::Core::OperationStatus::Succeeded;
case Azure::Core::Http::HttpStatusCode::NotFound:
return Azure::Core::OperationStatus::Running;
default:
throw Azure::Security::KeyVault::Common::KeyVaultException::CreateFromResponse(response);
}
}
} // namespace
std::unique_ptr<Azure::Core::Http::RawResponse>
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation::PollInternal(
Azure::Core::Context& context)
{
std::unique_ptr<Azure::Core::Http::RawResponse> rawResponse;
if (!IsDone())
{
rawResponse = m_pipeline->Send(
context,
Azure::Core::Http::HttpMethod::Get,
{_detail::KeysPath, m_value.Name(), m_value.Properties.Version});
m_status = CheckCompleted(*rawResponse);
if (m_status == Azure::Core::OperationStatus::Succeeded)
{
m_value
= _detail::KeyVaultKeySerializer::KeyVaultKeyDeserialize(m_value.Name(), *rawResponse);
}
}
// To ensure the success of calling Poll multiple times, even after operation is completed, a
// copy of the raw http response is returned instead of transfering the ownership of the raw
// response inside the Operation.
return rawResponse;
}
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation::RecoverDeletedKeyOperation(
std::shared_ptr<Azure::Security::KeyVault::Common::_internal::KeyVaultPipeline>
keyvaultPipeline,
Azure::Response<Azure::Security::KeyVault::Keys::KeyVaultKey> response)
: m_pipeline(keyvaultPipeline)
{
if (!response.HasValue())
{
throw Azure::Security::KeyVault::Common::KeyVaultException(
"The response does not contain a value.");
}
// The response becomes useless and the value and rawResponse are now owned by the
// DeleteKeyOperation. This is fine because the DeleteKeyOperation is what the delete key api
// will return.
m_value = response.ExtractValue();
m_rawResponse = response.ExtractRawResponse();
// Build the full url for continuation token. It is only used in case customers wants to use
// it on their own. The Operation uses the KeyVaultPipeline from the client which knows how to
// build this url.
m_continuationToken = m_pipeline->GetVaultUrl() + "/" + std::string(_detail::DeletedKeysPath)
+ "/" + m_value.Name();
}

View File

@ -3,4 +3,6 @@
cmake_minimum_required (VERSION 3.13)
add_subdirectory(get-key)
add_subdirectory(sample1-hello-world)
add_subdirectory(sample2-backup-and-restore)
add_subdirectory(sample3-get-keys)

View File

@ -0,0 +1,15 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.13)
project (sample1-hello-world LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable (
sample1-hello-world
sample1_hello_world.cpp
)
target_link_libraries(sample1-hello-world PRIVATE azure-security-keyvault-keys azure-identity)

View File

@ -0,0 +1,85 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @brief This sample provides the code implementation to use the Key Vault SDK client for C++
* to create, get, update, delete and purge a key.
*
* @remark The following environment variables must be set before running the sample.
* - AZURE_KEYVAULT_URL: To the KeyVault account url.
* - AZURE_TENANT_ID: Tenant id for the Azure account.
* - AZURE_CLIENT_ID: The client id to authenticate the request.
* - AZURE_CLIENT_SECRET: The secret id from the client id.
*
*/
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <azure/core.hpp>
#include <azure/identity.hpp>
#include <azure/keyvault/key_vault.hpp>
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
using namespace Azure::Security::KeyVault::Keys;
int main()
{
auto tenantId = std::getenv("AZURE_TENANT_ID");
auto clientId = std::getenv("AZURE_CLIENT_ID");
auto clientSecret = std::getenv("AZURE_CLIENT_SECRET");
auto credential
= std::make_shared<Azure::Identity::ClientSecretCredential>(tenantId, clientId, clientSecret);
KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
std::string rsaKeyName("CloudRsaKey" + Azure::Core::Uuid::CreateUuid().ToString());
try
{
auto rsaKey = CreateRsaKeyOptions(rsaKeyName);
rsaKey.KeySize = 2048;
rsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
keyClient.CreateRsaKey(rsaKey);
KeyVaultKey cloudRsaKey = keyClient.GetKey(rsaKeyName).ExtractValue();
std::cout << "Key is returned with name " << cloudRsaKey.Name() << " and type "
<< KeyType::KeyTypeToString(cloudRsaKey.GetKeyType()) << std::endl;
cloudRsaKey.Properties.ExpiresOn
= cloudRsaKey.Properties.ExpiresOn.GetValue() + std::chrono::hours(24 * 365);
KeyVaultKey updatedKey = keyClient.UpdateKeyProperties(cloudRsaKey.Properties).ExtractValue();
std::cout << "Key's updated expiry time is " << updatedKey.Properties.ExpiresOn->ToString()
<< std::endl;
CreateRsaKeyOptions newRsaKey(rsaKeyName);
newRsaKey.KeySize = 4096;
newRsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
keyClient.CreateRsaKey(newRsaKey);
DeleteKeyOperation operation = keyClient.StartDeleteKey(rsaKeyName);
// You only need to wait for completion if you want to purge or recover the key.
operation.PollUntilDone(std::chrono::milliseconds(2000));
keyClient.PurgeDeletedKey(rsaKeyName);
}
catch (Azure::Core::Credentials::AuthenticationException const& e)
{
std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
return 1;
}
catch (Azure::Security::KeyVault::Common::KeyVaultException const& e)
{
std::cout << "KeyVault Client Exception happened:" << std::endl << e.Message << std::endl;
return 1;
}
return 0;
}

View File

@ -0,0 +1,15 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.13)
project (sample2-backup-and-restore LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable (
sample2-backup-and-restore
sample2_backup_and_restore.cpp
)
target_link_libraries(sample2-backup-and-restore PRIVATE azure-security-keyvault-keys azure-identity)

View File

@ -0,0 +1,143 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @brief This sample provides the code implementation to use the Key Vault SDK client for C++
* to back up and restore a key.
*
* @remark The following environment variables must be set before running the sample.
* - AZURE_KEYVAULT_URL: To the KeyVault account url.
* - AZURE_TENANT_ID: Tenant id for the Azure account.
* - AZURE_CLIENT_ID: The client id to authenticate the request.
* - AZURE_CLIENT_SECRET: The secret id from the client id.
*
*/
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <azure/core.hpp>
#include <azure/identity.hpp>
#include <azure/keyvault/key_vault.hpp>
#include <assert.h>
#include <chrono>
#include <fstream>
#include <iostream>
#include <memory>
#include <thread>
using namespace Azure::Security::KeyVault::Keys;
static void AssertKeysEqual(KeyProperties const& expected, KeyProperties const& actual);
int main()
{
auto tenantId = std::getenv("AZURE_TENANT_ID");
auto clientId = std::getenv("AZURE_CLIENT_ID");
auto clientSecret = std::getenv("AZURE_CLIENT_SECRET");
auto credential
= std::make_shared<Azure::Identity::ClientSecretCredential>(tenantId, clientId, clientSecret);
KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
std::string rsaKeyName("CloudRsaKey" + Azure::Core::Uuid::CreateUuid().ToString());
try
{
auto rsaKey = CreateRsaKeyOptions(rsaKeyName);
rsaKey.KeySize = 2048;
rsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
std::cout << "\t-Create Key" << std::endl;
auto storedKey = keyClient.CreateRsaKey(rsaKey).ExtractValue();
size_t backUpSize = 0;
{
std::cout << "\t-Backup Key" << std::endl;
std::vector<uint8_t> backupKey(keyClient.BackupKey(rsaKeyName).ExtractValue());
backUpSize = backupKey.size();
// save data to file
std::cout << "\t-Save to file" << std::endl;
std::ofstream savedFile;
savedFile.open("backup.dat");
for (auto const& data : backupKey)
{
savedFile << data;
}
savedFile.close();
}
// backup key is destroy at this point as it is out of the scope.
// The storage account key is no longer in use, so you delete it.
std::cout << "\t-Delete and purge key" << std::endl;
DeleteKeyOperation operation = keyClient.StartDeleteKey(rsaKeyName);
// You only need to wait for completion if you want to purge or recover the key.
operation.PollUntilDone(std::chrono::milliseconds(2000));
keyClient.PurgeDeletedKey(rsaKeyName);
// let's wait for one minute so we know the key was purged.
std::this_thread::sleep_for(std::chrono::seconds(60));
// Restore the key from the file backup
std::cout << "\t-Read from file." << std::endl;
std::ifstream inFile;
inFile.open("backup.dat");
std::vector<uint8_t> inMemoryBackup(backUpSize);
inFile >> inMemoryBackup.data();
inFile.close();
std::cout << "\t-Restore Key" << std::endl;
auto restoredKey = keyClient.RestoreKeyBackup(inMemoryBackup).ExtractValue();
AssertKeysEqual(storedKey.Properties, restoredKey.Properties);
operation = keyClient.StartDeleteKey(rsaKeyName);
// You only need to wait for completion if you want to purge or recover the key.
operation.PollUntilDone(std::chrono::milliseconds(2000));
keyClient.PurgeDeletedKey(rsaKeyName);
}
catch (Azure::Core::Credentials::AuthenticationException const& e)
{
std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
return 1;
}
catch (Azure::Security::KeyVault::Common::KeyVaultException const& e)
{
std::cout << "KeyVault Client Exception happened:" << std::endl << e.Message << std::endl;
return 1;
}
return 0;
}
template <class T>
static inline bool CompareNullableT(Azure::Nullable<T> const& left, Azure::Nullable<T> const& right)
{
if (!left.HasValue() && !right.HasValue())
{
return true;
}
if (left.HasValue() && !right.HasValue())
{
return false;
}
if (!left.HasValue() && right.HasValue())
{
return false;
}
return left.GetValue() == right.GetValue();
}
void AssertKeysEqual(KeyProperties const& expected, KeyProperties const& actual)
{
#if defined(NDEBUG)
// Use (void) to silent unused warnings.
(void)expected;
(void)actual;
#endif
assert(expected.Name == actual.Name);
assert(expected.Version == actual.Version);
assert(expected.Managed == actual.Managed);
assert(expected.RecoveryLevel == actual.RecoveryLevel);
assert(CompareNullableT(expected.ExpiresOn, actual.ExpiresOn));
assert(CompareNullableT(expected.NotBefore, actual.NotBefore));
}

View File

@ -0,0 +1,15 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# SPDX-License-Identifier: MIT
cmake_minimum_required (VERSION 3.13)
project (sample3-get-keys LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_executable (
sample3-get-keys
sample3_get_keys.cpp
)
target_link_libraries(sample3-get-keys PRIVATE azure-security-keyvault-keys azure-identity)

View File

@ -0,0 +1,183 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @brief This sample provides the code implementation to use the Key Vault SDK client for C++
* to list keys and versions of a given key, and list deleted keys in a soft-delete enabled Key
* Vault.
*
* @remark The following environment variables must be set before running the sample.
* - AZURE_KEYVAULT_URL: To the KeyVault account url.
* - AZURE_TENANT_ID: Tenant id for the Azure account.
* - AZURE_CLIENT_ID: The client id to authenticate the request.
* - AZURE_CLIENT_SECRET: The secret id from the client id.
*
*/
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <azure/core.hpp>
#include <azure/identity.hpp>
#include <azure/keyvault/key_vault.hpp>
#include <chrono>
#include <fstream>
#include <iostream>
#include <memory>
#include <thread>
using namespace Azure::Security::KeyVault::Keys;
int main()
{
auto tenantId = std::getenv("AZURE_TENANT_ID");
auto clientId = std::getenv("AZURE_CLIENT_ID");
auto clientSecret = std::getenv("AZURE_CLIENT_SECRET");
auto credential
= std::make_shared<Azure::Identity::ClientSecretCredential>(tenantId, clientId, clientSecret);
KeyClient keyClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
try
{
std::string rsaKeyName("CloudRsaKey-" + Azure::Core::Uuid::CreateUuid().ToString());
auto rsaKey = CreateRsaKeyOptions(rsaKeyName);
rsaKey.KeySize = 2048;
rsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
std::string ecKeyName("CloudEcKey-" + Azure::Core::Uuid::CreateUuid().ToString());
auto ecKey = CreateEcKeyOptions(ecKeyName);
ecKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
std::cout << "\t-Create Keys" << std::endl;
keyClient.CreateRsaKey(rsaKey);
keyClient.CreateEcKey(ecKey);
std::cout << "\t-List Keys" << std::endl;
for (auto keysSinglePage = keyClient.GetPropertiesOfKeysSinglePage().ExtractValue();;)
{
for (auto const& key : keysSinglePage.Items)
{
if (key.Managed)
{
continue;
}
auto keyWithType = keyClient.GetKey(key.Name).ExtractValue();
std::cout << "Key is returned with name: " << keyWithType.Name()
<< " and type: " << KeyType::KeyTypeToString(keyWithType.GetKeyType())
<< std::endl;
}
if (!keysSinglePage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetPropertiesOfKeysSinglePageOptions options;
options.ContinuationToken = keysSinglePage.ContinuationToken.GetValue();
keysSinglePage = keyClient.GetPropertiesOfKeysSinglePage(options).ExtractValue();
}
// update key
CreateRsaKeyOptions newRsaKey(rsaKeyName);
newRsaKey.KeySize = 4096;
newRsaKey.ExpiresOn = std::chrono::system_clock::now() + std::chrono::hours(24 * 365);
keyClient.CreateRsaKey(newRsaKey);
// List key versions
std::cout << "\t-List Key versions" << std::endl;
for (auto keyVersionsSinglePage
= keyClient.GetPropertiesOfKeyVersionsSinglePage(rsaKeyName).ExtractValue();
;)
{
for (auto const& key : keyVersionsSinglePage.Items)
{
std::cout << "Key's version: " << key.Version << " with name: " << key.Name << std::endl;
}
if (!keyVersionsSinglePage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetPropertiesOfKeyVersionsSinglePageOptions options;
options.ContinuationToken = keyVersionsSinglePage.ContinuationToken.GetValue();
keyVersionsSinglePage
= keyClient.GetPropertiesOfKeyVersionsSinglePage(rsaKeyName, options).ExtractValue();
}
std::cout << "\t-Delete Keys" << std::endl;
DeleteKeyOperation rsaOperation = keyClient.StartDeleteKey(rsaKeyName);
DeleteKeyOperation ecOperation = keyClient.StartDeleteKey(ecKeyName);
// You only need to wait for completion if you want to purge or recover the key.
rsaOperation.PollUntilDone(std::chrono::milliseconds(2000));
ecOperation.PollUntilDone(std::chrono::milliseconds(2000));
std::cout << "\t-List Deleted Keys" << std::endl;
// Start getting the first page.
for (auto keysDeletedPage = keyClient.GetDeletedKeysSinglePage().ExtractValue();;)
{
for (auto const& key : keysDeletedPage.Items)
{
std::cout << "Deleted key's name: " << key.Name()
<< ", recovery level: " << key.Properties.RecoveryLevel
<< " and recovery Id: " << key.RecoveryId << std::endl;
}
if (!keysDeletedPage.ContinuationToken.HasValue())
{
// No more pages for the response, break the loop
break;
}
// Get the next page
GetDeletedKeysSinglePageOptions options;
options.ContinuationToken = keysDeletedPage.ContinuationToken.GetValue();
keysDeletedPage = keyClient.GetDeletedKeysSinglePage(options).ExtractValue();
}
// If the keyvault is soft-delete enabled, then for permanent deletion, deleted keys needs to be
// purged.
keyClient.PurgeDeletedKey(rsaKeyName);
keyClient.PurgeDeletedKey(ecKeyName);
}
catch (Azure::Core::Credentials::AuthenticationException const& e)
{
std::cout << "Authentication Exception happened:" << std::endl << e.what() << std::endl;
return 1;
}
catch (Azure::Security::KeyVault::Common::KeyVaultException const& e)
{
std::cout << "KeyVault Client Exception happened:" << std::endl << e.Message << std::endl;
return 1;
}
return 0;
}
template <class T>
static inline bool CompareNullableT(Azure::Nullable<T> const& left, Azure::Nullable<T> const& right)
{
if (!left.HasValue() && !right.HasValue())
{
return true;
}
if (left.HasValue() && !right.HasValue())
{
return false;
}
if (!left.HasValue() && right.HasValue())
{
return false;
}
return left.GetValue() == right.GetValue();
}

View File

@ -37,9 +37,12 @@ gtest_discover_tests(azure-security-keyvault-keys-test
################## Live Tests ##########################
add_executable (
azure-security-keyvault-keys-test-live
key_client_backup_test_live.cpp
key_client_create_test_live.cpp
key_client_delete_test_live.cpp
key_client_get_test_live.cpp
key_client_import_test_live.cpp
key_client_update_test_live.cpp
main.cpp
key_client_base_test.hpp
)

View File

@ -0,0 +1,84 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "gtest/gtest.h"
#include "key_client_base_test.hpp"
#include <azure/core/base64.hpp>
#include <azure/core/internal/json/json.hpp>
#include <azure/keyvault/key_vault.hpp>
#include <azure/keyvault/keys/details/key_constants.hpp>
#include <iostream>
#include <string>
#include <thread>
using namespace Azure::Security::KeyVault::Keys::Test;
using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Core::Json::_internal;
TEST_F(KeyVaultClientTest, BackupKey)
{
KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName = GetUniqueName();
std::cout
<< std::endl
<< "Backup key test takes more than 2 minutes since it needs to wait for purge to complete.";
{
std::cout << std::endl << "- Create key";
auto response = keyClient.CreateKey(keyName, JsonWebKeyType::Ec);
CheckValidResponse(response);
}
// backup
std::cout << std::endl << "- Backup key";
auto backUpResponse = keyClient.BackupKey(keyName);
CheckValidResponse(backUpResponse);
{
// Delete
std::cout << std::endl << "- Delete key";
auto response = keyClient.StartDeleteKey(keyName);
response.PollUntilDone(std::chrono::milliseconds(1000));
}
{
// Purge
std::cout << std::endl << "- Purge key";
auto response = keyClient.PurgeDeletedKey(keyName);
CheckValidResponse(response, Azure::Core::Http::HttpStatusCode::NoContent);
// Purge can take up to 2 min
std::this_thread::sleep_for(std::chrono::minutes(2));
}
{ // Check key is gone
EXPECT_THROW(keyClient.GetKey(keyName), Azure::Security::KeyVault::Common::KeyVaultException);
}
{
// Restore
std::cout << std::endl << "- Restore key";
auto respone = keyClient.RestoreKeyBackup(*backUpResponse);
CheckValidResponse(backUpResponse);
}
{
// Check key is restored
auto response = keyClient.GetKey(keyName);
CheckValidResponse(response);
EXPECT_EQ(keyName, response->Name());
}
{
// Delete
std::cout << std::endl << "- Clean";
auto response = keyClient.StartDeleteKey(keyName);
response.PollUntilDone(std::chrono::milliseconds(1000));
}
{
// Purge
auto response = keyClient.PurgeDeletedKey(keyName);
CheckValidResponse(response, Azure::Core::Http::HttpStatusCode::NoContent);
}
}

View File

@ -10,10 +10,12 @@
#include <gtest/gtest.h>
#include <azure/core/context.hpp>
#include <azure/core/uuid.hpp>
#include <azure/identity/client_secret_credential.hpp>
#include <azure/keyvault/key_vault.hpp>
#include <cstdio>
#include <iostream>
namespace Azure { namespace Security { namespace KeyVault { namespace Keys { namespace Test {
@ -43,13 +45,80 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys { nam
Azure::Response<T>& response,
Azure::Core::Http::HttpStatusCode expectedCode = Azure::Core::Http::HttpStatusCode::Ok)
{
auto rawResponse = response.ExtractRawResponse();
auto const& rawResponse = response.GetRawResponse();
EXPECT_EQ(
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
rawResponse->GetStatusCode()),
rawResponse.GetStatusCode()),
static_cast<typename std::underlying_type<Azure::Core::Http::HttpStatusCode>::type>(
expectedCode));
}
static inline std::string GetUniqueName() { return Azure::Core::Uuid::CreateUuid().ToString(); }
static inline void CleanUpKeyVault(KeyClient const& keyClient)
{
std::vector<DeletedKey> deletedKeys;
GetDeletedKeysSinglePageOptions options;
while (true)
{
auto keyResponse = keyClient.GetDeletedKeysSinglePage(options);
for (auto& key : keyResponse->Items)
{
deletedKeys.emplace_back(key);
}
if (!keyResponse->ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse->ContinuationToken;
}
if (deletedKeys.size() > 0)
{
for (auto& deletedKey : deletedKeys)
{
keyClient.PurgeDeletedKey(deletedKey.Name());
}
// Wait for purge is completed
std::this_thread::sleep_for(std::chrono::minutes(1));
}
}
static inline void RemoveAllKeysFromVault(KeyClient const& keyClient, bool waitForPurge = true)
{
std::vector<DeleteKeyOperation> deletedKeys;
GetPropertiesOfKeysSinglePageOptions options;
while (true)
{
auto keyResponse = keyClient.GetPropertiesOfKeysSinglePage(options);
for (auto& key : keyResponse->Items)
{
deletedKeys.emplace_back(keyClient.StartDeleteKey(key.Name));
}
if (!keyResponse->ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse->ContinuationToken;
}
if (deletedKeys.size() > 0)
{
std::cout << std::endl
<< "Cleaning vault. " << deletedKeys.size()
<< " Will be deleted and purged now...";
for (auto& deletedKey : deletedKeys)
{
auto readyToPurgeKey = deletedKey.PollUntilDone(std::chrono::milliseconds(1000));
keyClient.PurgeDeletedKey(readyToPurgeKey->Name());
std::cout << std::endl << "Deleted and purged key: " + readyToPurgeKey->Name();
}
std::cout << std::endl << "Complete purge operation.";
// Wait for purge is completed
if (waitForPurge)
{
std::this_thread::sleep_for(std::chrono::minutes(1));
}
}
}
};
}}}}} // namespace Azure::Security::KeyVault::Keys::Test

View File

@ -19,7 +19,7 @@ using namespace Azure::Security::KeyVault::Keys::Test;
TEST_F(KeyVaultClientTest, CreateKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("createKey");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -40,7 +40,7 @@ TEST_F(KeyVaultClientTest, CreateKey)
TEST_F(KeyVaultClientTest, CreateKeyWithOptions)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("createKeyWithOptions");
auto keyName = GetUniqueName();
Azure::Security::KeyVault::Keys::CreateKeyOptions options;
options.KeyOperations.push_back(Azure::Security::KeyVault::Keys::KeyOperation::Sign());
@ -75,7 +75,7 @@ TEST_F(KeyVaultClientTest, CreateKeyWithOptions)
TEST_F(KeyVaultClientTest, CreateKeyWithTags)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("myKeyWithOptionsTags");
auto keyName = GetUniqueName();
Azure::Security::KeyVault::Keys::CreateKeyOptions options;
options.Tags.emplace("one", "value=1");
@ -102,7 +102,7 @@ TEST_F(KeyVaultClientTest, CreateKeyWithTags)
TEST_F(KeyVaultClientTest, CreateEcKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("createEcKey");
auto keyName = GetUniqueName();
{
auto ecKey = Azure::Security::KeyVault::Keys::CreateEcKeyOptions(keyName);
@ -123,7 +123,7 @@ TEST_F(KeyVaultClientTest, CreateEcKey)
TEST_F(KeyVaultClientTest, CreateEcKeyWithCurve)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("createEcKey");
auto keyName = GetUniqueName();
{
auto ecKey = Azure::Security::KeyVault::Keys::CreateEcKeyOptions(keyName);
@ -150,7 +150,7 @@ TEST_F(KeyVaultClientTest, CreateEcKeyWithCurve)
TEST_F(KeyVaultClientTest, CreateRsaKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("createRsaKey");
auto keyName = GetUniqueName();
{
auto rsaKey = Azure::Security::KeyVault::Keys::CreateRsaKeyOptions(keyName, false);
@ -173,7 +173,7 @@ TEST_F(KeyVaultClientTest, CreateRsaKey)
TEST_F(KeyVaultClientTest, CreateEcHsmKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultHsmUrl, m_credential);
std::string keyName("createEcHsmKey");
auto keyName = GetUniqueName();
{
auto ecHsmKey = Azure::Security::KeyVault::Keys::CreateEcKeyOptions(keyName, true);
@ -202,7 +202,7 @@ TEST_F(KeyVaultClientTest, CreateEcHsmKey)
TEST_F(KeyVaultClientTest, CreateRsaHsmKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultHsmUrl, m_credential);
std::string keyName("createRsaHsmKey");
auto keyName = GetUniqueName();
{
auto rsaHsmKey = Azure::Security::KeyVault::Keys::CreateRsaKeyOptions(keyName, true);

View File

@ -44,7 +44,7 @@ using namespace Azure::Security::KeyVault::Keys::Test;
TEST_F(KeyVaultClientTest, DeleteKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("deleteThisKey");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -69,12 +69,26 @@ TEST_F(KeyVaultClientTest, DeleteKey)
// Will throw and fail test if test takes more than 3 minutes (token cancelled)
auto keyResponse = keyResponseLRO.PollUntilDone(std::chrono::milliseconds(1000), cancelToken);
}
{
// recover
auto recoverOperation = keyClient.StartRecoverDeletedKey(keyName);
auto keyResponse = recoverOperation.PollUntilDone(std::chrono::milliseconds(500));
auto key = keyResponse.ExtractValue();
// Delete again for purging
auto deleteOp = keyClient.StartDeleteKey(key.Name());
deleteOp.PollUntilDone(std::chrono::milliseconds(200));
}
{
// Purge
auto response = keyClient.PurgeDeletedKey(keyName);
CheckValidResponse(response, Azure::Core::Http::HttpStatusCode::NoContent);
}
}
TEST_F(KeyVaultClientTest, DeleteKeyOperationPoll)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("deleteThisKeyPoll");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -98,7 +112,7 @@ TEST_F(KeyVaultClientTest, DeleteKeyOperationPoll)
TEST_F(KeyVaultClientTest, DeleteInvalidKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("thisKeyDoesNotExists");
auto keyName = GetUniqueName();
auto wasThrown = false;
try
@ -125,7 +139,7 @@ TEST_F(KeyVaultClientTest, DeleteInvalidKey)
TEST_F(KeyVaultClientTest, DoubleDelete)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("DeleteMeTwoTimes");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -163,7 +177,7 @@ TEST_F(KeyVaultClientTest, DoubleDelete)
TEST_F(KeyVaultClientTest, DoubleDeleteBeforePollComplete)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("DeleteMeBeforePollComplete1");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -199,7 +213,7 @@ TEST_F(KeyVaultClientTest, DoubleDeleteBeforePollComplete)
TEST_F(KeyVaultClientTest, CreateDeletedKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("YouCanCreateMeAfterYouDeletedMe");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -239,7 +253,7 @@ TEST_F(KeyVaultClientTest, CreateDeletedKey)
TEST_F(KeyVaultClientTest, CreateDeletedKeyBeforePollComplete)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("YouCanCreateMeAfterYouDeletedMeEvenBeforePollComplete");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -276,7 +290,7 @@ TEST_F(KeyVaultClientTest, CreateDeletedKeyBeforePollComplete)
TEST_F(KeyVaultClientTest, GetDeletedKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
std::string keyName("deleteThisKeyAndGetItFromDeleteKeys1wwxx3x4");
auto keyName = GetUniqueName();
{
auto keyResponse
@ -302,7 +316,7 @@ TEST_F(KeyVaultClientTest, GetDeletedKey)
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));
Azure::Security::KeyVault::Keys::KeyType::KeyTypeToString(expectedType),
Azure::Security::KeyVault::Keys::KeyType::KeyTypeToString(deletedKey.Key.KeyType));
}
}

View File

@ -15,17 +15,167 @@
#include <string>
using namespace Azure::Security::KeyVault::Keys::Test;
using namespace Azure::Security::KeyVault::Keys;
TEST_F(KeyVaultClientTest, GetKey)
TEST_F(KeyVaultClientTest, GetSingleKey)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
KeyClient keyClient(m_keyVaultUrl, m_credential);
// Assuming and RS Key exists in the KeyVault Account.
std::string keyName("testKey");
std::string keyName(GetUniqueName());
auto createKeyResponse = keyClient.CreateEcKey(CreateEcKeyOptions(keyName));
CheckValidResponse(createKeyResponse);
auto keyResponse = keyClient.GetKey(keyName);
CheckValidResponse(keyResponse);
auto key = keyResponse.ExtractValue();
EXPECT_EQ(key.Name(), keyName);
EXPECT_EQ(key.GetKeyType(), Azure::Security::KeyVault::Keys::JsonWebKeyType::Rsa);
EXPECT_EQ(key.GetKeyType(), JsonWebKeyType::Ec);
}
TEST_F(KeyVaultClientTest, GetPropertiesOfKeysOnePage)
{
KeyClient keyClient(m_keyVaultUrl, m_credential);
// Delete and purge anything before starting the test to ensure test will work
RemoveAllKeysFromVault(keyClient);
// Create 5 keys
std::vector<std::string> keyNames;
for (int counter = 0; counter < 5; counter++)
{
auto name = GetUniqueName();
CreateEcKeyOptions options(name);
keyNames.emplace_back(name);
auto response = keyClient.CreateEcKey(options);
CheckValidResponse(response);
}
// Get Key properties
std::vector<KeyProperties> keyPropertiesList;
GetPropertiesOfKeysSinglePageOptions options;
while (true)
{
auto keyResponse = keyClient.GetPropertiesOfKeysSinglePage(options);
for (auto& key : keyResponse->Items)
{
keyPropertiesList.emplace_back(key);
}
if (!keyResponse->ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse->ContinuationToken;
}
EXPECT_EQ(keyNames.size(), keyPropertiesList.size());
for (auto const& keyProperties : keyPropertiesList)
{
// Check names are in the keyNames list
auto findKeyName = std::find(keyNames.begin(), keyNames.end(), keyProperties.Name);
EXPECT_NE(findKeyName, keyNames.end());
}
// Clean vault
RemoveAllKeysFromVault(keyClient, false);
}
TEST_F(KeyVaultClientTest, GetKeysVersionsOnePage)
{
KeyClient keyClient(m_keyVaultUrl, m_credential);
// Create 5 key versions
std::string keyName(GetUniqueName());
size_t expectedVersions = 5;
CreateEcKeyOptions createKeyOptions(keyName);
for (size_t counter = 0; counter < expectedVersions; counter++)
{
auto response = keyClient.CreateEcKey(createKeyOptions);
CheckValidResponse(response);
}
// Get Key versions
std::vector<KeyProperties> keyPropertiesList;
GetPropertiesOfKeyVersionsSinglePageOptions getKeyOptions;
while (true)
{
auto keyResponse = keyClient.GetPropertiesOfKeyVersionsSinglePage(keyName, getKeyOptions);
for (auto& key : keyResponse->Items)
{
keyPropertiesList.emplace_back(key);
}
if (!keyResponse->ContinuationToken)
{
break;
}
getKeyOptions.ContinuationToken = keyResponse->ContinuationToken;
}
EXPECT_EQ(expectedVersions, keyPropertiesList.size());
for (auto const& keyProperties : keyPropertiesList)
{
EXPECT_EQ(keyName, keyProperties.Name);
}
// Clean vault
RemoveAllKeysFromVault(keyClient, false);
}
TEST_F(KeyVaultClientTest, GetDeletedKeysOnePage)
{
KeyClient keyClient(m_keyVaultUrl, m_credential);
// Delete and purge anything before starting the test to ensure test will work
CleanUpKeyVault(keyClient);
// Create 5 keys
std::vector<std::string> keyNames;
for (int counter = 0; counter < 5; counter++)
{
auto name = GetUniqueName();
CreateEcKeyOptions options(name);
keyNames.emplace_back(name);
auto response = keyClient.CreateEcKey(options);
CheckValidResponse(response);
}
// Delete keys
std::vector<DeleteKeyOperation> operations;
for (auto const& keyName : keyNames)
{
operations.emplace_back(keyClient.StartDeleteKey(keyName));
}
// wait for all of the delete operations to complete
for (auto& operation : operations)
{
operation.PollUntilDone(std::chrono::milliseconds(1000));
}
// Get all deleted Keys
std::vector<DeletedKey> deletedKeys;
GetDeletedKeysSinglePageOptions options;
while (true)
{
auto keyResponse = keyClient.GetDeletedKeysSinglePage(options);
for (auto& key : keyResponse->Items)
{
deletedKeys.emplace_back(key);
}
if (!keyResponse->ContinuationToken)
{
break;
}
options.ContinuationToken = keyResponse->ContinuationToken;
}
EXPECT_EQ(keyNames.size(), deletedKeys.size());
for (auto const& deletedKey : deletedKeys)
{
// Check names are in the keyNames list
auto findKeyName = std::find(keyNames.begin(), keyNames.end(), deletedKey.Name());
EXPECT_NE(findKeyName, keyNames.end());
}
// Purge
for (auto const& keyName : keyNames)
{
keyClient.PurgeDeletedKey(keyName);
}
}

View File

@ -0,0 +1,67 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "gtest/gtest.h"
#include <azure/keyvault/common/internal/base64url.hpp>
#include <azure/keyvault/key_vault.hpp>
#include "key_client_base_test.hpp"
#include <string>
#include <thread>
using namespace Azure::Security::KeyVault::Keys::Test;
using namespace Azure::Security::KeyVault::Keys;
using namespace Azure::Security::KeyVault::Common::_internal;
TEST_F(KeyVaultClientTest, ImportKey)
{
KeyClient keyClient(m_keyVaultUrl, m_credential);
JsonWebKey key;
key.KeyType = JsonWebKeyType::Rsa;
// Values from https://docs.microsoft.com/en-us/rest/api/keyvault/importkey/importkey
key.N = Base64Url::Base64UrlDecode(
"nKAwarTrOpzd1hhH4cQNdVTgRF-b0ubPD8ZNVf0UXjb62QuAk3Dn68ESThcF7SoDYRx2QVcfoMC9WCcuQUQDieJF-"
"lvJTSer1TwH72NBovwKlHvrXqEI0a6_uVYY5n-"
"soGt7qFZNbwQLdWWA6PrbqTLIkv6r01dcuhTiQQAn6OWEa0JbFvWfF1kILQIaSBBBaaQ4R7hZs7-"
"VQTHGD7J1xGteof4gw2VTiwNdcE8p5UG5b6S9KQwAeET4yB4KFPwQ3TDdzxJQ89mwYVi_"
"sgAIggN54hTq4oEKYJHBOMtFGIN0_HQ60ZSUnpOi87xNC-8VFqnv4rfTQ7nkK6XMvjMVfw");
key.E = Base64Url::Base64UrlDecode("AQAB");
key.D = Base64Url::Base64UrlDecode("GeT1_D5LAZa7qlC7WZ0DKJnOth8kcPrN0urTEFtWCbmHQWkAad_px_"
"VUpGp0BWDDzENbXbQcu4QCCdf4crve5eXt8dVI86OSah");
key.DP = Base64Url::Base64UrlDecode(
"ZGnmWx-Nca71z9a9vvT4g02iv3S-"
"3kSgmhl8JST09YQwK8tfiK7nXnNMtXJi2K4dLKKnLicGtCzB6W3mXdLcP2SUOWDOeStoBt8HEBT"
"4MrI1psCKqnBum78WkHju90rBFj99amkP6UeQy5EASAzgmKQu2nUaUnRV0lYP8LHMCkE");
key.DQ = Base64Url::Base64UrlDecode(
"dtpke0foFs04hPS6XYLA5lc7-1MAHfZKN4CkMAofwDqPmRQzCxpDJUk0gMWGJEdU_"
"Lqfbg22Py44cci0dczH36NW3UU5BL86T2_SPPDOuyX7kDscrIJCdowxQCGJHGRBEozM_"
"uTL46wu6UnUIv7m7cuGgodJyZBcdwpo6ziFink");
key.QI = Base64Url::Base64UrlDecode(
"Y9KD5GaHkAYmAqpOfAQUMr71QuAAaBb0APzMuUvoEYw39PD3_vJeh9HZ15QmJ8zCX10-"
"nlzUB-bWwvK-rGcJXbK4pArilr5MiaYv7e8h5eW2zs2_itDJ6Oebi-"
"wVbMhg7DvUTBbkCvPhhIedE4UlDQmMYP7RhzVVs7SfmkGs_DQ");
key.P = Base64Url::Base64UrlDecode(
"v1jeCPnuJQM2PW2690Q9KJk0Ulok8VFGjkcHUHVi3orKdy7y_"
"TCIWM6ZGvgFzI6abinzYbTEPKV4wFdMAwvOWmawXj5YrsoeB44_HXJ0ak_5_"
"iP6XXR8MLGXbd0ZqsxvAZyzMj9vyle7EN2cBod6aenI2QZoRDucPvjPwZsZotk");
key.Q = Base64Url::Base64UrlDecode(
"0Yv-Dj6qnvx_LL70lUnKA6MgHE_bUC4drl5ZNDDsUdUUYfxIK4G1rGU45kHGtp-Qg-"
"Uyf9s52ywLylhcVE3jfbjOgEozlSwKyhqfXkLpMLWHqOKj9fcfYd4PWKPOgpzWsqjA6fJbBUM"
"Yo0CU2G9cWCtVodO7sBJVSIZunWrAlBc");
std::string keyName(GetUniqueName());
auto response = keyClient.ImportKey(keyName, key);
CheckValidResponse(response);
{
// delete + purge
auto op = keyClient.StartDeleteKey(keyName);
op.PollUntilDone(std::chrono::milliseconds(1000));
keyClient.PurgeDeletedKey(keyName);
}
}

View File

@ -0,0 +1,49 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#if defined(_MSC_VER)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "gtest/gtest.h"
#include "key_client_base_test.hpp"
#include <azure/core/datetime.hpp>
#include <azure/keyvault/key_vault.hpp>
#include <azure/keyvault/keys/details/key_constants.hpp>
#include <string>
using namespace Azure::Security::KeyVault::Keys::Test;
using namespace Azure;
using namespace Azure::Security::KeyVault::Keys;
TEST_F(KeyVaultClientTest, UpdateProperties)
{
KeyClient keyClient(m_keyVaultUrl, m_credential);
auto keyName = GetUniqueName();
auto updateTo = DateTime::Parse("20301031T00:00:00Z", DateTime::DateFormat::Rfc3339);
{
auto keyResponse = keyClient.CreateKey(keyName, JsonWebKeyType::Ec);
CheckValidResponse(keyResponse);
auto keyVaultKey = keyResponse.ExtractValue();
EXPECT_EQ(keyVaultKey.Name(), keyName);
EXPECT_TRUE(keyVaultKey.Properties.Enabled);
EXPECT_TRUE(keyVaultKey.Properties.Enabled.GetValue());
// Update Key
keyVaultKey.Properties.Enabled = false;
keyVaultKey.Properties.ExpiresOn = updateTo;
auto updatedResponse = keyClient.UpdateKeyProperties(keyVaultKey.Properties);
CheckValidResponse(updatedResponse);
}
{
// Get updated key to check values
auto updatedKey = keyClient.GetKey(keyName);
CheckValidResponse(updatedKey);
auto key = updatedKey.ExtractValue();
EXPECT_TRUE(key.Properties.Enabled);
EXPECT_FALSE(key.Properties.Enabled.GetValue());
}
}