GetDeletedSecret API (#2666)

* fix doc warnings

* fix doc warnings

* GetDeletedSecretAPI

* undo uneeded changes

* comments
This commit is contained in:
George Arama 2021-07-27 13:10:14 -07:00 committed by GitHub
parent f5ab6a5252
commit 65d560dc11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 263 additions and 16 deletions

View File

@ -32,6 +32,7 @@ set(
inc/azure/keyvault/secrets/secret_client.hpp
inc/azure/keyvault/secrets/keyvault_secret.hpp
inc/azure/keyvault/keyvault_secrets.hpp
inc/azure/keyvault/secrets/keyvault_deleted_secret.hpp
)
set(

View File

@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Keyvault Deleted Secret definition
*/
#pragma once
#include <azure/core/datetime.hpp>
#include <azure/keyvault/secrets/keyvault_secret.hpp>
namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
/**
* @brief A Deleted Secret consisting of its previous id, attributes and its tags,
* as well as information on when it will be purged.
*/
struct KeyVaultDeletedSecret : public KeyVaultSecret
{
/**
* @brief A Deleted Secret consisting of its previous id, attributes and its tags,
* as well as information on when it will be purged.
*/
std::string RecoveryId;
/**
* @brief The time when the secret is scheduled to be purged, in UTC.
*/
Azure::DateTime ScheduledPurgeDate;
/**
* @brief The time when the secret was deleted, in UTC.
*/
Azure::DateTime DeletedDate;
/**
* @brief Default constructor.
*/
KeyVaultDeletedSecret() = default;
/**
* @brief Constructor.
*
* @param name Name of the deleted secret.
*/
KeyVaultDeletedSecret(std::string name) : KeyVaultSecret(std::move(name)) {}
};
}}}} // namespace Azure::Security::KeyVault::Secrets

View File

@ -10,7 +10,7 @@
#include <azure/keyvault/secrets/keyvault_secret_properties.hpp>
namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
struct KeyVaultSecret final
struct KeyVaultSecret
{
/**
* @brief The name of the secret.
@ -50,11 +50,28 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
*/
KeyVaultSecret(std::string name, std::string value)
: Name(std::move(name)), Value(std::move(value))
{
if (Name.empty())
{
throw std::invalid_argument("Name cannot be empty");
}
if (Value.empty())
{
throw std::invalid_argument("Value cannot be empty");
}
};
private:
KeyVaultSecret(std::string name) : Name(std::move(name))
{
if (Name.empty())
{
throw std::invalid_argument("Name cannot be empty");
}
}
friend struct KeyVaultDeletedSecret;
};
}}}} // namespace Azure::Security::KeyVault::Secrets

View File

@ -7,12 +7,21 @@
*/
#pragma once
#include "../src/private/keyvault_protocol.hpp"
#include "dll_import_export.hpp"
#include <azure/keyvault/secrets/keyvault_secret.hpp>
#include "azure/keyvault/secrets/keyvault_deleted_secret.hpp"
#include "azure/keyvault/secrets/keyvault_secret.hpp"
#include <azure/core/http/http.hpp>
#include <azure/core/internal/http/pipeline.hpp>
#include <azure/core/response.hpp>
#include <string>
namespace Azure { namespace Security { namespace KeyVault { namespace _detail {
class KeyVaultProtocolClient;
}}}} // namespace Azure::Security::KeyVault::_detail
namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
class ServiceVersion final {
@ -132,6 +141,20 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
std::string const& name,
GetSecretOptions const& options = GetSecretOptions(),
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief The Get Deleted Secret operation returns
* the specified deleted secret along with its attributes.
* This operation requires the secrets/get permission.
*
* @param name The name of the secret<span class="x x-first x-last">.</span>
* @param context The context for the operation can be used for request cancellation.
*
* @return The Secret wrapped in the Response.
*/
Azure::Response<KeyVaultDeletedSecret> GetDeletedSecret(
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
};
}}}} // namespace Azure::Security::KeyVault::Secrets

View File

@ -13,6 +13,7 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
/***************** KeyVault Secret *****************/
constexpr static const char SecretPath[] = "secrets";
static constexpr char const DeletedSecretPath[] = "deletedsecrets";
/******************* Secret property names ***********/
@ -31,6 +32,11 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
constexpr static const char ContentTypePropertyName[] = "contentType";
constexpr static const char RecoverableDaysPropertyName[] = "recoverableDays";
/**************** Deleted Secret property names ********/
constexpr static const char RecoveryIdPropertyName[] = "recoveryId";
constexpr static const char ScheduledPurgeDatePropertyName[] = "scheduledPurgeDate";
constexpr static const char DeletedDatePropertyName[] = "deletedDate";
/**************** KeyVault QueryParameters *********/
static constexpr char const ApiVersion[] = "api-version";
}}}}} // namespace Azure::Security::KeyVault::Secrets::_detail

View File

@ -8,9 +8,10 @@
*/
#pragma once
#include "azure/keyvault/secrets/keyvault_deleted_secret.hpp"
#include "azure/keyvault/secrets/keyvault_secret.hpp"
#include <azure/core/http/http.hpp>
#include <azure/core/internal/json/json.hpp>
#include <azure/keyvault/secrets/keyvault_secret.hpp>
using namespace Azure::Security::KeyVault::Secrets;
@ -76,4 +77,21 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
}
}
};
struct KeyVaultDeletedSecretSerializer final
{
// Creates a new deleted secret based on a name and an HTTP raw response.
static KeyVaultDeletedSecret KeyVaultDeletedSecretDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse);
// Create deleted secret from HTTP raw response only.
static KeyVaultDeletedSecret KeyVaultDeletedSecretDeserialize(
Azure::Core::Http::RawResponse const& rawResponse);
// Updates a deleted secret based on an HTTP raw response.
static void KeyVaultDeletedSecretDeserialize(
KeyVaultDeletedSecret& secret,
Azure::Core::Http::RawResponse const& rawResponse);
};
}}}}} // namespace Azure::Security::KeyVault::Secrets::_detail

View File

@ -64,4 +64,18 @@ Azure::Response<KeyVaultSecret> SecretClient::GetSecret(
{_detail::SecretPath, name, options.Version});
}
Azure::Response<KeyVaultDeletedSecret> SecretClient::GetDeletedSecret(
std::string const& name,
Azure::Core::Context const& context) const
{
return m_protocolClient->SendRequest<KeyVaultDeletedSecret>(
context,
Azure::Core::Http::HttpMethod::Get,
[&name](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(
name, rawResponse);
},
{_detail::DeletedSecretPath, name});
}
const ServiceVersion ServiceVersion::V7_2("7.2");

View File

@ -23,7 +23,8 @@ KeyVaultSecret KeyVaultSecretSerializer::KeyVaultSecretDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse)
{
KeyVaultSecret secret(name, "");
KeyVaultSecret secret;
secret.Name = name;
_detail::KeyVaultSecretSerializer::KeyVaultSecretDeserialize(secret, rawResponse);
return secret;
}
@ -45,7 +46,6 @@ void KeyVaultSecretSerializer::KeyVaultSecretDeserialize(
auto const& body = rawResponse.GetBody();
auto jsonParser = json::parse(body);
secret.Value = jsonParser[_detail::ValuePropertyName];
secret.Id = jsonParser[_detail::IdPropertyName];
secret.Properties.Id = secret.Id;
@ -103,6 +103,12 @@ void KeyVaultSecretSerializer::KeyVaultSecretDeserialize(
secret.Properties.Managed = jsonParser[_detail::ManagedPropertyName].get<bool>();
}
// value
if (jsonParser.contains(_detail::ValuePropertyName))
{
secret.Value = jsonParser[_detail::ValuePropertyName];
}
// key id
JsonOptional::SetIfExists<std::string>(
secret.Properties.KeyId, jsonParser, _detail::KeyIdPropertyName);
@ -111,3 +117,38 @@ void KeyVaultSecretSerializer::KeyVaultSecretDeserialize(
JsonOptional::SetIfExists<std::string>(
secret.Properties.ContentType, jsonParser, _detail::ContentTypePropertyName);
}
KeyVaultDeletedSecret KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(
std::string const& name,
Azure::Core::Http::RawResponse const& rawResponse)
{
KeyVaultDeletedSecret deletedSecret(name);
KeyVaultDeletedSecretDeserialize(deletedSecret, rawResponse);
return deletedSecret;
}
// Create deleted secret from HTTP raw response only.
KeyVaultDeletedSecret KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(
Azure::Core::Http::RawResponse const& rawResponse)
{
KeyVaultDeletedSecret deletedSecret;
KeyVaultDeletedSecretDeserialize(deletedSecret, rawResponse);
return deletedSecret;
}
// Updates a deleted secret based on an HTTP raw response.
void KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(
KeyVaultDeletedSecret& secret,
Azure::Core::Http::RawResponse const& rawResponse)
{
KeyVaultSecretSerializer::KeyVaultSecretDeserialize(secret, rawResponse);
auto const& body = rawResponse.GetBody();
auto jsonParser = json::parse(body);
secret.RecoveryId = jsonParser[_detail::RecoveryIdPropertyName];
secret.ScheduledPurgeDate = PosixTimeConverter::PosixTimeToDateTime(
jsonParser[_detail::ScheduledPurgeDatePropertyName]);
secret.DeletedDate
= PosixTimeConverter::PosixTimeToDateTime(jsonParser[_detail::DeletedDatePropertyName]);
}

View File

@ -22,5 +22,7 @@ int main()
// just a response, with a secret
auto response = secretClient.GetSecret("testSecret");
// just a response, with a secret
auto response2 = secretClient.GetDeletedSecret("someSecret");
return 0;
}

View File

@ -31,7 +31,7 @@ TEST(KeyVaultSecretSerializer, GetClientDeserializePartial3)
{
auto response = getPartialResponse();
KeyVaultSecret secret = KeyVaultSecret("name2", "");
KeyVaultSecret secret = KeyVaultSecret("name2", "a");
_detail::KeyVaultSecretSerializer::KeyVaultSecretDeserialize(secret, response);
runPartialExpect(secret);
@ -59,8 +59,42 @@ TEST(KeyVaultSecretSerializer, GetClientdeserializeFull3)
{
auto response = getFullResponse();
KeyVaultSecret secret = KeyVaultSecret("name2", "");
KeyVaultSecret secret = KeyVaultSecret("name2", "a");
_detail::KeyVaultSecretSerializer::KeyVaultSecretDeserialize(secret, response);
runFullExpect(secret);
}
TEST(KeyVaultDeletedSecretSerializer, GetDeletedClientDeserializeFull1)
{
auto response = getDeletedFullResponse();
KeyVaultDeletedSecret secret
= _detail::KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(response);
runFullExpect(secret, false);
runDeletedExtras(secret);
}
TEST(KeyVaultDeletedSecretSerializer, GetDeletedClientDeserializeFull2)
{
auto response = getDeletedFullResponse();
KeyVaultDeletedSecret secret
= _detail::KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(
"name1", response);
runFullExpect(secret, false);
runDeletedExtras(secret);
}
TEST(KeyVaultDeletedSecretSerializer, GetDeletedClientDeserializeFull3)
{
auto response = getDeletedFullResponse();
KeyVaultDeletedSecret secret = KeyVaultDeletedSecret("name2");
_detail::KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(secret, response);
runFullExpect(secret, false);
runDeletedExtras(secret);
}

View File

@ -3,8 +3,8 @@
#include "azure/core/http/http.hpp"
#include "azure/core/http/policies/policy.hpp"
#include "azure/keyvault/secrets/keyvault_deleted_secret.hpp"
#include "azure/keyvault/secrets/keyvault_secret.hpp"
#include <gtest/gtest.h>
#include <string>
@ -68,10 +68,43 @@ Azure::Core::Http::RawResponse getFullResponse()
return response;
}
void runPartialExpect(KeyVaultSecret& secret)
Azure::Core::Http::RawResponse getDeletedFullResponse()
{
auto response = Azure::Core::Http::RawResponse(1, 1, Azure::Core::Http::HttpStatusCode::Ok, "OK");
constexpr static const uint8_t responseBody[] = R"json({
"recoveryId": "https://myvault.vault.azure.net/deletedsecrets/GetDeletedSecretTest",
"deletedDate": 1493938433,
"scheduledPurgeDate": 1501714433,
"managed": true,
"id": "https://myvault.vault.azure.net/secrets/mysecretname/4387e9f3d6e14c459867679a90fd0f79",
"attributes": {
"enabled": true,
"created": 1493938433,
"updated": 1493938433,
"recoveryLevel": "Recoverable+Purgeable"
}
})json";
response.SetHeader(HttpShared::ContentType, "application/json");
response.SetHeader(HttpShared::MsRequestId, "1");
response.SetHeader(HttpShared::MsClientRequestId, "2");
response.SetBody(std::vector<uint8_t>(responseBody, responseBody + sizeof(responseBody)));
response.SetBodyStream(
std::make_unique<Azure::Core::IO::MemoryBodyStream>(responseBody, sizeof(responseBody) - 1));
return response;
}
void runPartialExpect(KeyVaultSecret& secret, bool expectValue = true)
{
if (expectValue)
{
EXPECT_EQ(secret.Value, "mysecretvalue");
}
EXPECT_EQ(secret.Name, "mysecretname");
EXPECT_EQ(secret.Value, "mysecretvalue");
EXPECT_EQ(secret.Properties.VaultUrl, "https://myvault.vault.azure.net");
EXPECT_EQ(secret.Properties.Version, "4387e9f3d6e14c459867679a90fd0f79");
EXPECT_EQ(secret.Properties.Id, secret.Id);
@ -79,16 +112,21 @@ void runPartialExpect(KeyVaultSecret& secret)
secret.Id,
"https://myvault.vault.azure.net/secrets/mysecretname/4387e9f3d6e14c459867679a90fd0f79");
EXPECT_EQ(secret.Properties.KeyId.HasValue(), false);
EXPECT_EQ(secret.Properties.Enabled.Value(), true);
EXPECT_EQ(secret.Properties.Managed, false);
EXPECT_EQ(secret.Properties.UpdatedOn.HasValue(), true);
EXPECT_EQ(secret.Properties.CreatedOn.HasValue(), true);
}
void runFullExpect(KeyVaultSecret& secret)
void runFullExpect(KeyVaultSecret& secret, bool expectValue = true)
{
if (expectValue)
{
EXPECT_EQ(secret.Value, "mysecretvalue");
EXPECT_EQ(secret.Properties.ContentType.Value(), "ct");
EXPECT_EQ(secret.Properties.KeyId.Value(), "kid");
}
EXPECT_EQ(secret.Name, "mysecretname");
EXPECT_EQ(secret.Value, "mysecretvalue");
EXPECT_EQ(secret.Properties.VaultUrl, "https://myvault.vault.azure.net");
EXPECT_EQ(secret.Properties.Version, "4387e9f3d6e14c459867679a90fd0f79");
EXPECT_EQ(secret.Properties.Id, secret.Id);
@ -97,10 +135,15 @@ void runFullExpect(KeyVaultSecret& secret)
"https://myvault.vault.azure.net/secrets/mysecretname/4387e9f3d6e14c459867679a90fd0f79");
EXPECT_EQ(secret.Properties.Enabled.Value(), true);
EXPECT_EQ(secret.Properties.Managed, true);
EXPECT_EQ(secret.Properties.ContentType.Value(), "ct");
EXPECT_EQ(secret.Properties.KeyId.Value(), "kid");
EXPECT_EQ(secret.Properties.UpdatedOn.HasValue(), true);
EXPECT_EQ(secret.Properties.CreatedOn.HasValue(), true);
}
void runDeletedExtras(KeyVaultDeletedSecret& secret)
{
EXPECT_EQ(
secret.RecoveryId, "https://myvault.vault.azure.net/deletedsecrets/GetDeletedSecretTest");
EXPECT_EQ(secret.ScheduledPurgeDate.ToString(), "2017-08-02T22:53:53Z");
EXPECT_EQ(secret.DeletedDate.ToString(), "2017-05-04T22:53:53Z");
}
} // namespace