[Keyvault] operation resume token fix (#2093)

Enable resume operations for keyvault
This commit is contained in:
Victor Vazquez 2021-04-14 11:55:09 -07:00 committed by GitHub
parent 1ea5afa961
commit ce4b285ddd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 153 additions and 12 deletions

View File

@ -10,6 +10,10 @@
- Removed `Azure::Security::KeyVault::Keys::JsonWebKey::to_json`.
### Bug Fixes
- Fix getting a resume token from delete and recover key operations.
## 4.0.0-beta.1 (2021-04-07)
### New Features

View File

@ -75,6 +75,14 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
std::shared_ptr<Azure::Security::KeyVault::_internal::KeyVaultPipeline> keyvaultPipeline,
Azure::Response<Azure::Security::KeyVault::Keys::DeletedKey> response);
DeleteKeyOperation(
std::shared_ptr<Azure::Security::KeyVault::_internal::KeyVaultPipeline> keyvaultPipeline,
std::string resumeToken)
: m_pipeline(keyvaultPipeline), m_value(DeletedKey(resumeToken)),
m_continuationToken(std::move(resumeToken))
{
}
/**
* @brief Get the #Azure::Core::Http::RawResponse of the operation request.
* @return A reference to an #Azure::Core::Http::RawResponse.

View File

@ -225,6 +225,18 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Construct a #DeletedKeyOperation from a resume token previously generated by calling
* #DeleteKeyOperation::GetResumeToken after a call to #StartDeleteKey().
*
* @param resumeToken A generated token from a DeletedKeyOperation.
* @param context A cancellation token controlling the request lifetime.
* @return Azure::Security::KeyVault::Keys::DeleteKeyOperation
*/
Azure::Security::KeyVault::Keys::DeleteKeyOperation ResumeDeleteKey(
std::string const& resumeToken,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Gets the public part of a deleted key.
*
@ -293,6 +305,19 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Construct a #RecoverDeletedKeyOperation from a resume token previously generated by
* calling #RecoverDeletedKeyOperation::GetResumeToken after a call to
* #StartRecoverDeletedKey().
*
* @param resumeToken A generated token from a StartRecoverDeletedKey.
* @param context A cancellation token controlling the request lifetime.
* @return Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation
*/
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation ResumeRecoverDeletedKey(
std::string const& resumeToken,
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.

View File

@ -71,6 +71,14 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Keys {
std::shared_ptr<Azure::Security::KeyVault::_internal::KeyVaultPipeline> keyvaultPipeline,
Azure::Response<Azure::Security::KeyVault::Keys::KeyVaultKey> response);
RecoverDeletedKeyOperation(
std::shared_ptr<Azure::Security::KeyVault::_internal::KeyVaultPipeline> keyvaultPipeline,
std::string resumeToken)
: m_pipeline(keyvaultPipeline), m_value(DeletedKey(resumeToken)),
m_continuationToken(std::move(resumeToken))
{
}
/**
* @brief Get the #Azure::Core::Http::RawResponse of the operation request.
* @return A reference to an #Azure::Core::Http::RawResponse.

View File

@ -60,11 +60,8 @@ Azure::Security::KeyVault::Keys::DeleteKeyOperation::DeleteKeyOperation(
m_value = response.Value;
m_rawResponse = std::move(response.RawResponse);
// 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();
// The key name is enough to be used as continuation token.
m_continuationToken = m_value.Name();
// The recoveryId is only returned if soft-delete is enabled.
// The LRO is considered completed for non soft-delete (key will be eventually removed).

View File

@ -202,6 +202,28 @@ Azure::Security::KeyVault::Keys::DeleteKeyOperation KeyClient::StartDeleteKey(
{_detail::KeysPath, name}));
}
Azure::Security::KeyVault::Keys::DeleteKeyOperation KeyClient::ResumeDeleteKey(
std::string const& resumeToken,
Azure::Core::Context const& context) const
{
Azure::Security::KeyVault::Keys::DeleteKeyOperation operation(m_pipeline, resumeToken);
// Need to fix this to use context directly. See:
// https://github.com/Azure/azure-sdk-for-cpp/issues/2091
operation.Poll(context.GetApplicationContext());
return operation;
}
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation KeyClient::ResumeRecoverDeletedKey(
std::string const& resumeToken,
Azure::Core::Context const& context) const
{
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation operation(m_pipeline, resumeToken);
// Need to fix this to use context directly. See:
// https://github.com/Azure/azure-sdk-for-cpp/issues/2091
operation.Poll(context.GetApplicationContext());
return operation;
}
Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation KeyClient::StartRecoverDeletedKey(
std::string const& name,
Azure::Core::Context const& context) const

View File

@ -62,9 +62,6 @@ Azure::Security::KeyVault::Keys::RecoverDeletedKeyOperation::RecoverDeletedKeyOp
m_value = response.Value;
m_rawResponse = std::move(response.RawResponse);
// 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();
// The key name is enough to resume the operation
m_continuationToken = m_value.Name();
}

View File

@ -62,8 +62,7 @@ TEST_F(KeyVaultClientTest, DeleteKey)
auto cancelToken = Azure::Core::Context::GetApplicationContext().WithDeadline(duration);
auto keyResponseLRO = keyClient.StartDeleteKey(keyName);
auto expectedStatusToken = m_keyVaultUrl
+ std::string(Azure::Security::KeyVault::Keys::_detail::DeletedKeysPath) + "/" + keyName;
auto expectedStatusToken = keyName;
EXPECT_EQ(keyResponseLRO.GetResumeToken(), expectedStatusToken);
// poll each second until key is soft-deleted
// Will throw and fail test if test takes more than 3 minutes (token cancelled)
@ -320,3 +319,84 @@ TEST_F(KeyVaultClientTest, GetDeletedKey)
Azure::Security::KeyVault::Keys::KeyType::KeyTypeToString(deletedKey.Key.KeyType));
}
}
TEST_F(KeyVaultClientTest, DeleteOperationResumeToken)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
auto keyName = GetUniqueName();
{
auto keyResponse
= keyClient.CreateKey(keyName, Azure::Security::KeyVault::Keys::JsonWebKeyType::Ec);
CheckValidResponse(keyResponse);
auto keyVaultKey = keyResponse.Value;
EXPECT_EQ(keyVaultKey.Name(), keyName);
}
std::string resumeToken;
{
auto keyResponseLRO = keyClient.StartDeleteKey(keyName);
resumeToken = keyResponseLRO.GetResumeToken();
}
// Resume operation from token
{
auto resumeOperation = keyClient.ResumeDeleteKey(resumeToken);
resumeOperation.PollUntilDone(std::chrono::milliseconds(500));
}
{
// recover
auto recoverOperation = keyClient.StartRecoverDeletedKey(keyName);
auto keyResponse = recoverOperation.PollUntilDone(std::chrono::milliseconds(500));
auto key = keyResponse.Value;
// 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, RecoverOperationResumeToken)
{
Azure::Security::KeyVault::Keys::KeyClient keyClient(m_keyVaultUrl, m_credential);
auto keyName = GetUniqueName();
{
auto keyResponse
= keyClient.CreateKey(keyName, Azure::Security::KeyVault::Keys::JsonWebKeyType::Ec);
CheckValidResponse(keyResponse);
auto keyVaultKey = keyResponse.Value;
EXPECT_EQ(keyVaultKey.Name(), keyName);
}
std::string resumeToken;
{
auto keyResponseLRO = keyClient.StartDeleteKey(keyName);
resumeToken = keyResponseLRO.GetResumeToken();
}
// Resume operation from token
{
auto resumeOperation = keyClient.ResumeDeleteKey(resumeToken);
resumeOperation.PollUntilDone(std::chrono::milliseconds(500));
}
{
// recover
auto recoverOperation = keyClient.StartRecoverDeletedKey(keyName);
resumeToken = recoverOperation.GetResumeToken();
}
{
// resume from token
auto resumeRecoveryOp = keyClient.ResumeRecoverDeletedKey(resumeToken);
auto keyResponse = resumeRecoveryOp.PollUntilDone(std::chrono::milliseconds(500));
auto key = keyResponse.Value;
// 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);
}
}