Backup / Restore secret (#2683)

* fix doc warnings

* get rid of bad merge

* fix doc warnings

* get rid of bad merge

* fix doc warnings

* get rid of bad merge

* code complete

* fix doc warnings

* get rid of bad merge

* fix doc warnings

* get rid of bad merge

* fix doc warnings

* get rid of bad merge

* test

* also restore

* new line

* fix doc warnings

* get rid of bad merge

* fix doc warnings

* get rid of bad merge

* fix doc warnings

* get rid of bad merge

* fixes for PR and build issues

* add header for linux build

* fix UT for mac

* remove offending issues

* rename from data to response

* added overload

* response -> result

* remove overload
This commit is contained in:
George Arama 2021-07-29 12:12:44 -07:00 committed by GitHub
parent 79143d4a1a
commit d830de4afc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 281 additions and 22 deletions

View File

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

View File

@ -9,6 +9,7 @@
#pragma once
#include "azure/keyvault/secrets/dll_import_export.hpp"
#include "azure/keyvault/secrets/keyvault_backup_secret.hpp"
#include "azure/keyvault/secrets/keyvault_deleted_secret.hpp"
#include "azure/keyvault/secrets/keyvault_secret.hpp"
#include "azure/keyvault/secrets/keyvault_secret_properties.hpp"

View File

@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Keyvault BackupSecretData definition
*/
#pragma once
#include <stdint.h>
#include <vector>
namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
/**
* @brief Represents a backed up secret.
*
*/
struct BackupSecretResult final
{
/**
* @brief The backed up secret.
*
*/
std::vector<uint8_t> Secret;
};
}}}} // namespace Azure::Security::KeyVault::Secrets

View File

@ -8,14 +8,15 @@
#pragma once
#include "dll_import_export.hpp"
#include "azure/keyvault/secrets/keyvault_backup_secret.hpp"
#include "azure/keyvault/secrets/keyvault_deleted_secret.hpp"
#include "azure/keyvault/secrets/keyvault_secret.hpp"
#include "dll_import_export.hpp"
#include <azure/core/http/http.hpp>
#include <azure/core/internal/http/pipeline.hpp>
#include <azure/core/response.hpp>
#include <stdint.h>
#include <string>
namespace Azure { namespace Security { namespace KeyVault { namespace _detail {
@ -235,6 +236,35 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
std::string const& version,
KeyvaultSecretProperties const& properties,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Back up the specified secret.
* Requests that a backup of the specified secret be downloaded to the client.
* All versions of the secret will be downloaded.
* This operation requires the secrets/backup 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 The backup blob containing the backed up secret.
*/
Azure::Response<BackupSecretResult> BackupSecret(
std::string const& name,
Azure::Core::Context const& context = Azure::Core::Context()) const;
/**
* @brief Restore a backed up secret to a vault.
* Restores a backed up secret, and all its versions, to a vault.
* This operation requires the secrets/restore permission.
*
* @param backup The backup payload as encoded vector of bytes.
* @param context The context for the operation can be used for request cancellation.
*
* @return The Secret wrapped in the Response.
*/
Azure::Response<KeyVaultSecret> RestoreSecretBackup(
std::vector<uint8_t> const& backup,
Azure::Core::Context const& context = Azure::Core::Context()) const;
};
}}}} // namespace Azure::Security::KeyVault::Secrets

View File

@ -14,6 +14,8 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
/***************** KeyVault Secret *****************/
constexpr static const char SecretPath[] = "secrets";
static constexpr char const DeletedSecretPath[] = "deletedsecrets";
static constexpr char const BackupSecretPath[] = "backup";
static constexpr char const RestoreSecretPath[] = "restore";
/******************* Secret property names ***********/

View File

@ -8,10 +8,13 @@
*/
#pragma once
#include "azure/keyvault/secrets/keyvault_backup_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/json/json.hpp>
#include <stdint.h>
#include <vector>
using namespace Azure::Security::KeyVault::Secrets;
@ -103,4 +106,15 @@ namespace Azure { namespace Security { namespace KeyVault { namespace Secrets {
static std::string KeyVaultSecretPropertiesSerialize(
KeyvaultSecretProperties const& properties);
};
struct KeyvaultBackupSecretSerializer final
{
static BackupSecretResult KeyvaultBackupSecretDeserialize(
Azure::Core::Http::RawResponse const& rawResponse);
};
struct KeyvaultRestoreSecretSerializer final
{
static std::string KeyvaultRestoreSecretSerialize(std::vector<uint8_t> const& backup);
};
}}}}} // namespace Azure::Security::KeyVault::Secrets::_detail

View File

@ -27,6 +27,8 @@ namespace {
constexpr static const char TelemetryName[] = "keyvault-secrets";
}
const ServiceVersion ServiceVersion::V7_2("7.2");
SecretClient::SecretClient(
std::string const& vaultUrl,
std::shared_ptr<Core::Credentials::TokenCredential const> credential,
@ -133,4 +135,32 @@ Azure::Response<KeyVaultSecret> SecretClient::UpdateSecretProperties(
return UpdateSecretProperties(name, options, properties, context);
}
const ServiceVersion ServiceVersion::V7_2("7.2");
Azure::Response<BackupSecretResult> SecretClient::BackupSecret(
std::string const& name,
Azure::Core::Context const& context) const
{
return m_protocolClient->SendRequest<BackupSecretResult>(
context,
Azure::Core::Http::HttpMethod::Post,
[](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyvaultBackupSecretSerializer::KeyvaultBackupSecretDeserialize(
rawResponse);
},
{_detail::SecretPath, name, _detail::BackupSecretPath});
}
Azure::Response<KeyVaultSecret> SecretClient::RestoreSecretBackup(
std::vector<uint8_t> const& backup,
Azure::Core::Context const& context) const
{
return m_protocolClient->SendRequest<KeyVaultSecret>(
context,
Azure::Core::Http::HttpMethod::Post,
[&backup]() {
return _detail::KeyvaultRestoreSecretSerializer::KeyvaultRestoreSecretSerialize(backup);
},
[](Azure::Core::Http::RawResponse const& rawResponse) {
return _detail::KeyVaultSecretSerializer::KeyVaultSecretDeserialize(rawResponse);
},
{_detail::SecretPath, _detail::RestoreSecretPath});
}

View File

@ -8,11 +8,12 @@
#include "private/secret_serializers.hpp"
#include "private/secret_constants.hpp"
#include <azure/core/base64.hpp>
#include <azure/core/internal/json/json.hpp>
#include <azure/core/internal/json/json_optional.hpp>
#include <azure/core/internal/json/json_serializable.hpp>
using namespace Azure::Core::_internal;
using namespace Azure::Core::Json::_internal;
using Azure::Core::_internal::PosixTimeConverter;
using namespace Azure::Security::KeyVault::Secrets;
@ -157,41 +158,41 @@ void KeyVaultDeletedSecretSerializer::KeyVaultDeletedSecretDeserialize(
std::string KeyVaultSecretSerializer::KeyVaultSecretSerialize(KeyVaultSecret const& parameters)
{
json payload;
using namespace Azure::Security::KeyVault::Secrets::_detail;
// value is required
payload[ValuePropertyName] = parameters.Value;
// all else is optional
JsonOptional::SetFromNullable(
parameters.Properties.ContentType, payload, ContentTypePropertyName);
parameters.Properties.ContentType, payload, _detail::ContentTypePropertyName);
json attributes;
JsonOptional::SetFromNullable<Azure::DateTime, int64_t>(
parameters.Properties.CreatedOn,
attributes,
CreatedPropertyName,
_detail::CreatedPropertyName,
PosixTimeConverter::DateTimeToPosixTime);
JsonOptional::SetFromNullable(parameters.Properties.Enabled, attributes, EnabledPropertyName);
JsonOptional::SetFromNullable(
parameters.Properties.Enabled, attributes, _detail::EnabledPropertyName);
JsonOptional::SetFromNullable<Azure::DateTime, int64_t>(
parameters.Properties.ExpiresOn,
attributes,
ExpPropertyName,
_detail::ExpPropertyName,
PosixTimeConverter::DateTimeToPosixTime);
JsonOptional::SetFromNullable<Azure::DateTime, int64_t>(
parameters.Properties.NotBefore,
attributes,
NbfPropertyName,
_detail::NbfPropertyName,
PosixTimeConverter::DateTimeToPosixTime);
JsonOptional::SetFromNullable(
parameters.Properties.RecoverableDays, attributes, RecoverableDaysPropertyName);
parameters.Properties.RecoverableDays, attributes, _detail::RecoverableDaysPropertyName);
JsonOptional::SetFromNullable(
parameters.Properties.RecoveryLevel, attributes, RecoveryLevelPropertyName);
parameters.Properties.RecoveryLevel, attributes, _detail::RecoveryLevelPropertyName);
JsonOptional::SetFromNullable<Azure::DateTime, int64_t>(
parameters.Properties.UpdatedOn,
attributes,
UpdatedPropertyName,
_detail::UpdatedPropertyName,
PosixTimeConverter::DateTimeToPosixTime);
// optional tags
@ -236,3 +237,23 @@ std::string KeyVaultSecretPropertiesSerializer::KeyVaultSecretPropertiesSerializ
return payload.dump();
}
BackupSecretResult KeyvaultBackupSecretSerializer::KeyvaultBackupSecretDeserialize(
Azure::Core::Http::RawResponse const& rawResponse)
{
auto const& body = rawResponse.GetBody();
auto jsonParser = json::parse(body);
auto encodedResult = jsonParser[_detail::ValuePropertyName].get<std::string>();
BackupSecretResult data;
data.Secret = Base64Url::Base64UrlDecode(encodedResult);
return data;
}
std::string KeyvaultRestoreSecretSerializer::KeyvaultRestoreSecretSerialize(
std::vector<uint8_t> const& backup)
{
json payload;
payload[_detail::ValuePropertyName] = Base64Url::Base64UrlEncode(backup);
return payload.dump();
}

View File

@ -19,14 +19,17 @@ int main()
SecretClient secretClient(std::getenv("AZURE_KEYVAULT_URL"), credential);
// just a response, with a secret
auto response = secretClient.GetSecret("testSecret");
response.Value.Properties.ContentType = "weqeq";
GetSecretOptions options;
// auto response = secretClient.GetSecret("testSecret");
// response.Value.Properties.ContentType = "weqeq";
// GetSecretOptions options;
response = secretClient.UpdateSecretProperties(
response.Value.Name, response.Value.Properties.Version, response.Value.Properties);
// response = secretClient.UpdateSecretProperties(
// response.Value.Name, response.Value.Properties.Version, response.Value.Properties);
// just a response, with a secret
auto response3 = secretClient.GetDeletedSecret("someSecret");
// auto response3 = secretClient.GetDeletedSecret("someSecret");
auto response4 = secretClient.BackupSecret("someSecret2");
auto response5 = secretClient.RestoreSecretBackup(response4.Value.Secret);
return 0;
}

View File

@ -17,7 +17,9 @@ add_executable (
secret_get_client_deserialize_test.cpp
secret_set_parameters_serializer_test.cpp
secret_update_properties_test.cpp
)
secret_backup_deserialize_test.cpp
secret_backup_deserialize_test.hpp
)
if (MSVC)
target_compile_options(azure-security-keyvault-secrets-test PUBLIC /wd6326 /wd26495 /wd26812)

View File

@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "secret_backup_deserialize_test.hpp"
#include "../src/private/secret_serializers.hpp"
#include "azure/keyvault/secrets/secret_client.hpp"
using namespace Azure::Security::KeyVault::Secrets;
using namespace Azure::Security::KeyVault::Secrets::_test;
using namespace Azure::Security::KeyVault::Secrets::_detail;
using namespace Azure::Core::Json::_internal;
TEST(KeyvaultBackupSecretSerializer, EmptyValue)
{
auto response = BackupHelpers::GetEmptyResponse();
auto secret = _detail::KeyvaultBackupSecretSerializer::KeyvaultBackupSecretDeserialize(response);
EXPECT_EQ(secret.Secret.size(), size_t(0));
}
TEST(KeyvaultBackupSecretSerializer, FullValue)
{
auto response = BackupHelpers::GetFullResponse();
auto secret = _detail::KeyvaultBackupSecretSerializer::KeyvaultBackupSecretDeserialize(response);
EXPECT_EQ(secret.Secret.size(), size_t(10));
std::string str(secret.Secret.begin(), secret.Secret.end());
EXPECT_EQ(str, "my name is");
}
TEST(KeyvaultRestoreSecretSerializer, EmptyValue)
{
std::string str = "";
auto data = std::vector<uint8_t>(str.begin(), str.end());
auto secret = _detail::KeyvaultRestoreSecretSerializer::KeyvaultRestoreSecretSerialize(data);
auto jsonParser = json::parse(secret);
EXPECT_EQ(secret.size(), size_t(12));
EXPECT_EQ(jsonParser["value"].get<std::string>().empty(), true);
}
TEST(KeyvaultRestoreSecretSerializer, SomeValue)
{
std::string str = "my name is";
auto data = std::vector<uint8_t>(str.begin(), str.end());
auto secret = _detail::KeyvaultRestoreSecretSerializer::KeyvaultRestoreSecretSerialize(data);
auto jsonParser = json::parse(secret);
EXPECT_EQ(secret.size(), size_t(26));
EXPECT_EQ(jsonParser["value"], "bXkgbmFtZSBpcw");
}

View File

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#include "azure/keyvault/secrets/keyvault_deleted_secret.hpp"
#include "azure/keyvault/secrets/keyvault_secret.hpp"
#include <azure/core/http/http.hpp>
#include <azure/core/http/policies/policy.hpp>
#include <gtest/gtest.h>
#include <string>
using namespace Azure::Security::KeyVault::Secrets;
using namespace Azure::Core::Http::_internal;
namespace Azure { namespace Security { namespace KeyVault { namespace Secrets { namespace _test {
struct BackupHelpers
{
static Azure::Core::Http::RawResponse GetEmptyResponse()
{
auto response
= Azure::Core::Http::RawResponse(1, 1, Azure::Core::Http::HttpStatusCode::Ok, "OK");
constexpr static const uint8_t responseBody[] = R"json({
"value": ""
}
)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;
}
static Azure::Core::Http::RawResponse GetFullResponse()
{
auto response
= Azure::Core::Http::RawResponse(1, 1, Azure::Core::Http::HttpStatusCode::Ok, "OK");
constexpr static const uint8_t responseBody[] = R"json({
"value": "bXkgbmFtZSBpcw=="
}
)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;
}
static Azure::Core::Http::RawResponse GetIncorrectResponse()
{
auto response
= Azure::Core::Http::RawResponse(1, 1, Azure::Core::Http::HttpStatusCode::Ok, "OK");
constexpr static const uint8_t responseBody[] = R"json({
"value": "my name is"
}
)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;
}
};
}}}}} // namespace Azure::Security::KeyVault::Secrets::_test

View File

@ -1,10 +1,10 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
#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 <azure/core/http/http.hpp>
#include <azure/core/http/policies/policy.hpp>
#include <gtest/gtest.h>
#include <string>