Add Account SAS and Blob SAS (#353)
* Add Account SAS and Blob SAS * add doc for sas * remove Nones * remove Nones
This commit is contained in:
parent
b380dfb76a
commit
9d1566c5ea
@ -28,6 +28,7 @@ set(AZURE_STORAGE_COMMON_HEADER
|
||||
inc/common/storage_uri_builder.hpp
|
||||
inc/common/storage_version.hpp
|
||||
inc/common/xml_wrapper.hpp
|
||||
inc/common/account_sas_builder.hpp
|
||||
)
|
||||
|
||||
set(AZURE_STORAGE_COMMON_SOURCE
|
||||
@ -39,6 +40,7 @@ set(AZURE_STORAGE_COMMON_SOURCE
|
||||
src/common/storage_error.cpp
|
||||
src/common/storage_uri_builder.cpp
|
||||
src/common/xml_wrapper.cpp
|
||||
src/common/account_sas_builder.cpp
|
||||
)
|
||||
|
||||
add_library(azure-storage-common ${AZURE_STORAGE_COMMON_HEADER} ${AZURE_STORAGE_COMMON_SOURCE})
|
||||
@ -93,6 +95,7 @@ set (AZURE_STORAGE_BLOB_HEADER
|
||||
inc/blobs/append_blob_client.hpp
|
||||
inc/blobs/blob_options.hpp
|
||||
inc/blobs/blob_responses.hpp
|
||||
inc/blobs/blob_sas_builder.hpp
|
||||
inc/blobs/protocol/blob_rest_client.hpp
|
||||
)
|
||||
|
||||
@ -103,6 +106,7 @@ set (AZURE_STORAGE_BLOB_SOURCE
|
||||
src/blobs/block_blob_client.cpp
|
||||
src/blobs/page_blob_client.cpp
|
||||
src/blobs/append_blob_client.cpp
|
||||
src/blobs/blob_sas_builder.cpp
|
||||
)
|
||||
|
||||
add_library(azure-storage-blob ${AZURE_STORAGE_BLOB_HEADER} ${AZURE_STORAGE_BLOB_SOURCE})
|
||||
|
||||
313
sdk/storage/inc/blobs/blob_sas_builder.hpp
Normal file
313
sdk/storage/inc/blobs/blob_sas_builder.hpp
Normal file
@ -0,0 +1,313 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "blobs/protocol/blob_rest_client.hpp"
|
||||
#include "common/account_sas_builder.hpp"
|
||||
#include "nullable.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
/**
|
||||
* @brief Specifies which resources are accessible via the shared access signature.
|
||||
*/
|
||||
enum class BlobSasResource
|
||||
{
|
||||
/**
|
||||
* @brief Grants access to the content and metadata of any blob in the container, and to
|
||||
* the list of blobs in the container.
|
||||
*/
|
||||
Container,
|
||||
|
||||
/**
|
||||
* @brief Grants access to the content and metadata of the blob.
|
||||
*/
|
||||
Blob,
|
||||
|
||||
/**
|
||||
* @brief Grants access to the content and metadata of the specific snapshot, but not
|
||||
* the corresponding root blob.
|
||||
*/
|
||||
BlobSnapshot,
|
||||
|
||||
/**
|
||||
* @brief Grants access to the content and metadata of the specific version, but not the
|
||||
* corresponding root blob.
|
||||
*/
|
||||
BlobVersion,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The list of permissions that can be set for a blob container's access policy.
|
||||
*/
|
||||
enum class BlobContainerSasPermissions
|
||||
{
|
||||
/**
|
||||
* @brief Indicates that Read is permitted.
|
||||
*/
|
||||
Read = 1,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Write is permitted.
|
||||
*/
|
||||
Write = 2,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Delete is permitted.
|
||||
*/
|
||||
Delete = 4,
|
||||
|
||||
/**
|
||||
* @brief Indicates that List is permitted.
|
||||
*/
|
||||
List = 8,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Add is permitted.
|
||||
*/
|
||||
Add = 16,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Create is permitted.
|
||||
*/
|
||||
Create = 32,
|
||||
|
||||
/**
|
||||
* @brief Indicates that reading and writing tags is permitted.
|
||||
*/
|
||||
Tags = 64,
|
||||
|
||||
/**
|
||||
* @brief Indicates that deleting previous blob version is permitted.
|
||||
*/
|
||||
DeleteVersion = 128,
|
||||
|
||||
/**
|
||||
* @beirf Indicates that all permissions are set.
|
||||
*/
|
||||
All = ~0,
|
||||
};
|
||||
|
||||
inline BlobContainerSasPermissions operator|(
|
||||
BlobContainerSasPermissions lhs,
|
||||
BlobContainerSasPermissions rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<BlobContainerSasPermissions>;
|
||||
return static_cast<BlobContainerSasPermissions>(
|
||||
static_cast<type>(lhs) | static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
inline BlobContainerSasPermissions operator&(
|
||||
BlobContainerSasPermissions lhs,
|
||||
BlobContainerSasPermissions rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<BlobContainerSasPermissions>;
|
||||
return static_cast<BlobContainerSasPermissions>(
|
||||
static_cast<type>(lhs) & static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The list of permissions that can be set for a blob's access policy.
|
||||
*/
|
||||
enum class BlobSasPermissions
|
||||
{
|
||||
/**
|
||||
* @brief Indicates that Read is permitted.
|
||||
*/
|
||||
Read = 1,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Write is permitted.
|
||||
*/
|
||||
Write = 2,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Delete is permitted.
|
||||
*/
|
||||
|
||||
Delete = 4,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Add is permitted.
|
||||
*/
|
||||
Add = 8,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Create is permitted.
|
||||
*/
|
||||
Create = 16,
|
||||
|
||||
/**
|
||||
* @brief Indicates that reading and writing tags is permitted.
|
||||
*/
|
||||
Tags = 32,
|
||||
|
||||
/**
|
||||
* @brief Indicates that deleting previous blob version is permitted.
|
||||
*/
|
||||
DeleteVersion = 64,
|
||||
|
||||
/**
|
||||
* @beirf Indicates that all permissions are set.
|
||||
*/
|
||||
All = ~0,
|
||||
};
|
||||
|
||||
inline BlobSasPermissions operator|(BlobSasPermissions lhs, BlobSasPermissions rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<BlobSasPermissions>;
|
||||
return static_cast<BlobSasPermissions>(static_cast<type>(lhs) | static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
inline BlobSasPermissions operator&(BlobSasPermissions lhs, BlobSasPermissions rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<BlobSasPermissions>;
|
||||
return static_cast<BlobSasPermissions>(static_cast<type>(lhs) & static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief BlobSasBuilder is used to generate a Shared Access Signature (SAS) for an Azure
|
||||
* Storage container or blob.
|
||||
*/
|
||||
struct BlobSasBuilder
|
||||
{
|
||||
/**
|
||||
* @brief The storage service version to use to authenticate requests made with this
|
||||
* shared access signature, and the service version to use when handling requests made with this
|
||||
* shared access signature.
|
||||
*/
|
||||
std::string Version = c_APIVersion;
|
||||
|
||||
/**
|
||||
* @brief The optional signed protocol field specifies the protocol permitted for a
|
||||
* request made with the SAS.
|
||||
*/
|
||||
SasProtocol Protocol;
|
||||
|
||||
/**
|
||||
* @brief Optionally specify the time at which the shared access signature becomes
|
||||
* valid.
|
||||
*/
|
||||
std::string StartsOn;
|
||||
|
||||
/**
|
||||
* @brief The time at which the shared access signature becomes invalid. This field must
|
||||
* be omitted if it has been specified in an associated stored access policy.
|
||||
*/
|
||||
std::string ExpiresOn;
|
||||
|
||||
/**
|
||||
* @brief Specifies an IP address or a range of IP addresses from which to accept
|
||||
* requests. If the IP address from which the request originates does not match the IP address
|
||||
* or address range specified on the SAS token, the request is not authenticated. When
|
||||
* specifying a range of IP addresses, note that the range is inclusive.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> IPRange;
|
||||
|
||||
/**
|
||||
* @brief An optional unique value up to 64 characters in length that correlates to an
|
||||
* access policy specified for the container.
|
||||
*/
|
||||
std::string Identifier;
|
||||
|
||||
/**
|
||||
* @brief The name of the blob container being made accessible.
|
||||
*/
|
||||
std::string ContainerName;
|
||||
|
||||
/**
|
||||
* @brief The name of the blob being made accessible, or empty for a container SAS..
|
||||
*/
|
||||
std::string BlobName;
|
||||
|
||||
/**
|
||||
* @brief The name of the blob snapshot being made accessible, or empty for a container
|
||||
* SAS and blob SAS.
|
||||
*/
|
||||
std::string Snapshot;
|
||||
|
||||
/**
|
||||
* @brief The id of the blob version being made accessible, or empty for a container
|
||||
* SAS, blob SAS and blob snapshot SAS.
|
||||
*/
|
||||
std::string BlobVersionId;
|
||||
|
||||
/**
|
||||
* @brief Specifies which resources are accessible via the shared access signature.
|
||||
*/
|
||||
BlobSasResource Resource;
|
||||
|
||||
/**
|
||||
* @brief Override the value returned for Cache-Control response header..
|
||||
*/
|
||||
std::string CacheControl;
|
||||
|
||||
/**
|
||||
* @brief Override the value returned for Content-Disposition response header..
|
||||
*/
|
||||
std::string ContentDisposition;
|
||||
|
||||
/**
|
||||
* @brief Override the value returned for Content-Encoding response header..
|
||||
*/
|
||||
std::string ContentEncoding;
|
||||
|
||||
/**
|
||||
* @brief Override the value returned for Content-Language response header..
|
||||
*/
|
||||
std::string ContentLanguage;
|
||||
|
||||
/**
|
||||
* @brief Override the value returned for Content-Type response header..
|
||||
*/
|
||||
std::string ContentType;
|
||||
|
||||
/**
|
||||
* @brief Sets the permissions for the blob container SAS.
|
||||
*
|
||||
* @param
|
||||
* permissions The allowed permissions.
|
||||
*/
|
||||
void SetPermissions(BlobContainerSasPermissions permissions);
|
||||
|
||||
/**
|
||||
* @brief Sets the permissions for the blob SAS.
|
||||
*
|
||||
* @param permissions The
|
||||
* allowed permissions.
|
||||
*/
|
||||
void SetPermissions(BlobSasPermissions permissions);
|
||||
|
||||
/**
|
||||
* @brief Uses the SharedKeyCredential to sign this shared access signature, to produce
|
||||
* the proper SAS query parameters for authentication requests.
|
||||
*
|
||||
* @param credential
|
||||
* The storage account's shared key credential.
|
||||
* @return The SAS query parameters used for
|
||||
* authenticating requests.
|
||||
*/
|
||||
std::string ToSasQueryParameters(const SharedKeyCredential& credential);
|
||||
|
||||
/**
|
||||
* @brief Uses an account's user delegation key to sign this shared access signature, to
|
||||
* produce the proper SAS query parameters for authentication requests.
|
||||
*
|
||||
* @param
|
||||
* credential UserDelegationKey retruned from BlobServiceClient.GetUserDelegationKey.
|
||||
* @param accountName The name of the storage account.
|
||||
* @return The SAS query parameters
|
||||
* used for authenticating requests.
|
||||
*/
|
||||
std::string ToSasQueryParameters(
|
||||
const UserDelegationKey& userDelegationKey,
|
||||
const std::string& accountName);
|
||||
|
||||
private:
|
||||
std::string Permissions;
|
||||
};
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
@ -28,6 +28,8 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
Azure::Core::Http::BodyStream,
|
||||
std::function<void(Azure::Core::Http::BodyStream*)>>;
|
||||
|
||||
constexpr static const char* c_APIVersion = "2019-12-12";
|
||||
|
||||
struct AbortCopyBlobInfo
|
||||
{
|
||||
}; // struct AbortCopyBlobInfo
|
||||
@ -1006,7 +1008,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, url);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -1109,7 +1111,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
request.AddHeader("Content-Length", std::to_string(body->Length()));
|
||||
request.AddQueryParameter("restype", "service");
|
||||
request.AddQueryParameter("comp", "userdelegationkey");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -1608,7 +1610,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("restype", "container");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -1684,7 +1686,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Delete, url);
|
||||
request.AddQueryParameter("restype", "container");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -1752,7 +1754,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, url);
|
||||
request.AddQueryParameter("restype", "container");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -1852,7 +1854,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("restype", "container");
|
||||
request.AddQueryParameter("comp", "metadata");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -1931,7 +1933,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, url);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -2022,7 +2024,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, url);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -2726,7 +2728,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Get, url);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -2935,7 +2937,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Delete, url);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3012,7 +3014,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3069,7 +3071,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Head, url);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3290,7 +3292,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "properties");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3416,7 +3418,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "metadata");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3518,7 +3520,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "tier");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3591,7 +3593,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3716,7 +3718,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3785,7 +3787,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "snapshot");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -3916,7 +3918,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url, body.get());
|
||||
request.AddHeader("Content-Length", std::to_string(body->Length()));
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -4087,7 +4089,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
request.AddHeader("Content-Length", std::to_string(body->Length()));
|
||||
request.AddQueryParameter("comp", "block");
|
||||
request.AddQueryParameter("blockid", options.BlockId);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -4201,7 +4203,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "block");
|
||||
request.AddQueryParameter("blockid", options.BlockId);
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -4357,7 +4359,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url, body.get());
|
||||
request.AddHeader("Content-Length", std::to_string(body->Length()));
|
||||
request.AddQueryParameter("comp", "blocklist");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -4506,7 +4508,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
= BlockListTypeOptionToString(options.ListType.GetValue());
|
||||
request.AddQueryParameter("blocklisttype", block_list_type_option);
|
||||
}
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -4746,7 +4748,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -4919,7 +4921,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url, body.get());
|
||||
request.AddHeader("Content-Length", std::to_string(body->Length()));
|
||||
request.AddQueryParameter("comp", "page");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -5078,7 +5080,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "page");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -5236,7 +5238,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "page");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -5371,7 +5373,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "properties");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -5489,7 +5491,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
{
|
||||
request.AddQueryParameter("prevsnapshot", options.PreviousSnapshot.GetValue());
|
||||
}
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -5606,7 +5608,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "incrementalcopy");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -5858,7 +5860,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
unused(body);
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -6019,7 +6021,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
= Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url, body.get());
|
||||
request.AddHeader("Content-Length", std::to_string(body->Length()));
|
||||
request.AddQueryParameter("comp", "appendblock");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
@ -6164,7 +6166,7 @@ namespace Azure { namespace Storage { namespace Blobs {
|
||||
auto request = Azure::Core::Http::Request(Azure::Core::Http::HttpMethod::Put, url);
|
||||
request.AddHeader("Content-Length", "0");
|
||||
request.AddQueryParameter("comp", "appendblock");
|
||||
request.AddHeader("x-ms-version", "2019-12-12");
|
||||
request.AddHeader("x-ms-version", c_APIVersion);
|
||||
if (options.Timeout.HasValue())
|
||||
{
|
||||
request.AddQueryParameter("timeout", std::to_string(options.Timeout.GetValue()));
|
||||
|
||||
268
sdk/storage/inc/common/account_sas_builder.hpp
Normal file
268
sdk/storage/inc/common/account_sas_builder.hpp
Normal file
@ -0,0 +1,268 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/constants.hpp"
|
||||
#include "common/storage_credential.hpp"
|
||||
#include "nullable.hpp"
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
/**
|
||||
* @brief Defines the protocols permitted for Storage requests made with a shared access
|
||||
* signature.
|
||||
*/
|
||||
enum class SasProtocol
|
||||
{
|
||||
/**
|
||||
* @brief Only requests issued over HTTPS or HTTP will be permitted.
|
||||
*/
|
||||
HttpsAndHtttp,
|
||||
|
||||
/**
|
||||
* @brief Only requests issued over HTTPS will be permitted.
|
||||
*/
|
||||
HttpsOnly,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Specifies the resource types accessible from an account level shared access
|
||||
* signature.
|
||||
*/
|
||||
enum class AccountSasResource
|
||||
{
|
||||
/**
|
||||
* @brief Indicates whether service-level APIs are accessible from this shared access
|
||||
* signature.
|
||||
*/
|
||||
Service = 1,
|
||||
|
||||
/**
|
||||
* @brief Indicates whether blob container-level APIs are accessible from this shared
|
||||
* access signature.
|
||||
*/
|
||||
Container = 2,
|
||||
|
||||
/**
|
||||
* @brief Indicates whether object-level APIs for blobs, queue messages, and files are
|
||||
* accessible from this shared access signature.
|
||||
*/
|
||||
Object = 4,
|
||||
|
||||
/**
|
||||
* @brief Indicates all service-level APIs are accessible from this shared access
|
||||
* signature.
|
||||
*/
|
||||
All = ~0,
|
||||
};
|
||||
|
||||
inline AccountSasResource operator|(AccountSasResource lhs, AccountSasResource rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<AccountSasResource>;
|
||||
return static_cast<AccountSasResource>(static_cast<type>(lhs) | static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
inline AccountSasResource operator&(AccountSasResource lhs, AccountSasResource rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<AccountSasResource>;
|
||||
return static_cast<AccountSasResource>(static_cast<type>(lhs) & static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Specifies the services accessible from an account level shared access signature.
|
||||
*/
|
||||
enum class AccountSasServices
|
||||
{
|
||||
/**
|
||||
* @brief Indicates whether Azure Blob Storage resources are accessible from the shared
|
||||
* access signature.
|
||||
*/
|
||||
Blobs = 1,
|
||||
|
||||
/**
|
||||
* @brief Indicates whether Azure Queue Storage resources are accessible from the shared
|
||||
* access signature.
|
||||
*/
|
||||
Queue = 2,
|
||||
|
||||
/**
|
||||
* @brief Indicates whether Azure File Storage resources are accessible from the shared
|
||||
* access signature.
|
||||
*/
|
||||
Files = 4,
|
||||
|
||||
/**
|
||||
* @brief Indicates all services are accessible from the shared
|
||||
* access signature.
|
||||
*/
|
||||
All = ~0,
|
||||
};
|
||||
|
||||
inline AccountSasServices operator|(AccountSasServices lhs, AccountSasServices rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<AccountSasServices>;
|
||||
return static_cast<AccountSasServices>(static_cast<type>(lhs) | static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
inline AccountSasServices operator&(AccountSasServices lhs, AccountSasServices rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<AccountSasServices>;
|
||||
return static_cast<AccountSasServices>(static_cast<type>(lhs) & static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The list of permissions that can be set for an account's access policy.
|
||||
*/
|
||||
enum class AccountSasPermissions
|
||||
{
|
||||
/**
|
||||
* @brief Indicates that Read is permitted.
|
||||
*/
|
||||
Read = 1,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Write is permitted.
|
||||
*/
|
||||
Write = 2,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Delete is permitted.
|
||||
*/
|
||||
Delete = 4,
|
||||
|
||||
/**
|
||||
* @brief Indicates that deleting previous blob version is permitted.
|
||||
*/
|
||||
DeleteVersion = 8,
|
||||
|
||||
/**
|
||||
* @brief Indicates that List is permitted.
|
||||
*/
|
||||
List = 16,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Add is permitted.
|
||||
*/
|
||||
Add = 32,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Create is permitted.
|
||||
*/
|
||||
Create = 64,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Update is permitted.
|
||||
*/
|
||||
Update = 128,
|
||||
|
||||
/**
|
||||
* @brief Indicates that Process is permitted.
|
||||
*/
|
||||
Process = 256,
|
||||
|
||||
/**
|
||||
* @brief Indicates that reading and writing tags is permitted.
|
||||
*/
|
||||
Tags = 512,
|
||||
|
||||
/**
|
||||
* @brief Indicates that filtering by tags is permitted.
|
||||
*/
|
||||
Filter = 1024,
|
||||
|
||||
/**
|
||||
* @brief Indicates that all permissions are set.
|
||||
*/
|
||||
All = ~0,
|
||||
};
|
||||
|
||||
inline AccountSasPermissions operator|(AccountSasPermissions lhs, AccountSasPermissions rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<AccountSasPermissions>;
|
||||
return static_cast<AccountSasPermissions>(static_cast<type>(lhs) | static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
inline AccountSasPermissions operator&(AccountSasPermissions lhs, AccountSasPermissions rhs)
|
||||
{
|
||||
using type = std::underlying_type_t<AccountSasPermissions>;
|
||||
return static_cast<AccountSasPermissions>(static_cast<type>(lhs) & static_cast<type>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AccountSasBuilder is used to generate an account level Shared Access Signature
|
||||
* (SAS) for Azure Storage services.
|
||||
*/
|
||||
struct AccountSasBuilder
|
||||
{
|
||||
/**
|
||||
* @brief The storage service version to use to authenticate requests made with this
|
||||
* shared access signature, and the service version to use when handling requests made with this
|
||||
* shared access signature.
|
||||
*/
|
||||
std::string Version = Details::c_defaultSasVersion;
|
||||
|
||||
/**
|
||||
* @brief The optional signed protocol field specifies the protocol permitted for a
|
||||
* request made with the SAS.
|
||||
*/
|
||||
SasProtocol Protocol = SasProtocol::HttpsOnly;
|
||||
|
||||
/**
|
||||
* @brief Optionally specify the time at which the shared access signature becomes
|
||||
* valid.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> StartsOn;
|
||||
|
||||
/**
|
||||
* @brief The time at which the shared access signature becomes invalid. This field must
|
||||
* be omitted if it has been specified in an associated stored access policy.
|
||||
*/
|
||||
std::string ExpiresOn;
|
||||
|
||||
/**
|
||||
* @brief Specifies an IP address or a range of IP addresses from which to accept
|
||||
* requests. If the IP address from which the request originates does not match the IP address
|
||||
* or address range specified on the SAS token, the request is not authenticated. When
|
||||
* specifying a range of IP addresses, note that the range is inclusive.
|
||||
*/
|
||||
Azure::Core::Nullable<std::string> IPRange;
|
||||
|
||||
/**
|
||||
* @brief The services associated with the shared access signature. The user is
|
||||
* restricted to operations with the specified services.
|
||||
*/
|
||||
AccountSasServices Services;
|
||||
|
||||
/**
|
||||
* The resource types associated with the shared access signature. The user is
|
||||
* restricted to operations on the specified resources.
|
||||
*/
|
||||
AccountSasResource ResourceTypes;
|
||||
|
||||
/**
|
||||
* @brief Sets the permissions for an account SAS.
|
||||
*
|
||||
* @param permissions The
|
||||
* allowed permissions.
|
||||
*/
|
||||
void SetPermissions(AccountSasPermissions permissions);
|
||||
|
||||
/**
|
||||
* @brief Uses the SharedKeyCredential to sign this shared access signature, to produce
|
||||
* the proper SAS query parameters for authentication requests.
|
||||
*
|
||||
* @param credential
|
||||
* The storage account's shared key credential.
|
||||
* @return The SAS query parameters used for
|
||||
* authenticating requests.
|
||||
*/
|
||||
std::string ToSasQueryParameters(const SharedKeyCredential& credential);
|
||||
|
||||
private:
|
||||
std::string Permissions;
|
||||
};
|
||||
|
||||
}} // namespace Azure::Storage
|
||||
@ -17,4 +17,5 @@ namespace Azure { namespace Storage { namespace Details {
|
||||
constexpr static const char* c_HttpHeaderRequestId = "x-ms-request-id";
|
||||
constexpr static const char* c_HttpHeaderClientRequestId = "x-ms-client-request-id";
|
||||
constexpr static const char* c_HttpHeaderContentType = "content-type";
|
||||
constexpr static const char* c_defaultSasVersion = "2019-12-12";
|
||||
}}} // namespace Azure::Storage::Details
|
||||
|
||||
@ -11,6 +11,12 @@
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
struct AccountSasBuilder;
|
||||
namespace Blobs {
|
||||
struct BlobSasBuilder;
|
||||
}
|
||||
|
||||
struct SharedKeyCredential
|
||||
{
|
||||
explicit SharedKeyCredential(std::string accountName, std::string accountKey)
|
||||
@ -24,17 +30,19 @@ namespace Azure { namespace Storage {
|
||||
m_accountKey = std::move(accountKey);
|
||||
}
|
||||
|
||||
std::string AccountName;
|
||||
const std::string AccountName;
|
||||
|
||||
private:
|
||||
friend class SharedKeyPolicy;
|
||||
std::string GetAccountKey()
|
||||
friend struct Blobs::BlobSasBuilder;
|
||||
friend struct AccountSasBuilder;
|
||||
std::string GetAccountKey() const
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
return m_accountKey;
|
||||
}
|
||||
|
||||
std::mutex m_mutex;
|
||||
mutable std::mutex m_mutex;
|
||||
std::string m_accountKey;
|
||||
};
|
||||
|
||||
|
||||
173
sdk/storage/src/blobs/blob_sas_builder.cpp
Normal file
173
sdk/storage/src/blobs/blob_sas_builder.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "blobs/blob_sas_builder.hpp"
|
||||
#include "common/crypt.hpp"
|
||||
#include "common/storage_uri_builder.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Blobs {
|
||||
|
||||
void BlobSasBuilder::SetPermissions(BlobContainerSasPermissions permissions)
|
||||
{
|
||||
Permissions.clear();
|
||||
// The order matters
|
||||
if ((permissions & BlobContainerSasPermissions::Read) == BlobContainerSasPermissions::Read)
|
||||
{
|
||||
Permissions += "r";
|
||||
}
|
||||
if ((permissions & BlobContainerSasPermissions::Add) == BlobContainerSasPermissions::Add)
|
||||
{
|
||||
Permissions += "a";
|
||||
}
|
||||
if ((permissions & BlobContainerSasPermissions::Create) == BlobContainerSasPermissions::Create)
|
||||
{
|
||||
Permissions += "c";
|
||||
}
|
||||
if ((permissions & BlobContainerSasPermissions::Write) == BlobContainerSasPermissions::Write)
|
||||
{
|
||||
Permissions += "w";
|
||||
}
|
||||
if ((permissions & BlobContainerSasPermissions::Delete) == BlobContainerSasPermissions::Delete)
|
||||
{
|
||||
Permissions += "d";
|
||||
}
|
||||
if ((permissions & BlobContainerSasPermissions::DeleteVersion)
|
||||
== BlobContainerSasPermissions::DeleteVersion)
|
||||
{
|
||||
Permissions += "x";
|
||||
}
|
||||
if ((permissions & BlobContainerSasPermissions::List) == BlobContainerSasPermissions::List)
|
||||
{
|
||||
Permissions += "l";
|
||||
}
|
||||
if ((permissions & BlobContainerSasPermissions::Tags) == BlobContainerSasPermissions::Tags)
|
||||
{
|
||||
Permissions += "t";
|
||||
}
|
||||
}
|
||||
|
||||
void BlobSasBuilder::SetPermissions(BlobSasPermissions permissions)
|
||||
{
|
||||
Permissions.clear();
|
||||
// The order matters
|
||||
if ((permissions & BlobSasPermissions::Read) == BlobSasPermissions::Read)
|
||||
{
|
||||
Permissions += "r";
|
||||
}
|
||||
if ((permissions & BlobSasPermissions::Add) == BlobSasPermissions::Add)
|
||||
{
|
||||
Permissions += "a";
|
||||
}
|
||||
if ((permissions & BlobSasPermissions::Create) == BlobSasPermissions::Create)
|
||||
{
|
||||
Permissions += "c";
|
||||
}
|
||||
if ((permissions & BlobSasPermissions::Write) == BlobSasPermissions::Write)
|
||||
{
|
||||
Permissions += "w";
|
||||
}
|
||||
if ((permissions & BlobSasPermissions::Delete) == BlobSasPermissions::Delete)
|
||||
{
|
||||
Permissions += "d";
|
||||
}
|
||||
if ((permissions & BlobSasPermissions::DeleteVersion) == BlobSasPermissions::DeleteVersion)
|
||||
{
|
||||
Permissions += "x";
|
||||
}
|
||||
if ((permissions & BlobSasPermissions::Tags) == BlobSasPermissions::Tags)
|
||||
{
|
||||
Permissions += "t";
|
||||
}
|
||||
}
|
||||
|
||||
std::string BlobSasBuilder::ToSasQueryParameters(const SharedKeyCredential& credential)
|
||||
{
|
||||
std::string canonicalName = "/blob/" + credential.AccountName + "/" + ContainerName;
|
||||
if (Resource == BlobSasResource::Blob || Resource == BlobSasResource::BlobSnapshot)
|
||||
{
|
||||
canonicalName += "/" + BlobName;
|
||||
}
|
||||
std::string protocol;
|
||||
if (Protocol == SasProtocol::HttpsAndHtttp)
|
||||
{
|
||||
protocol = "https,http";
|
||||
}
|
||||
else
|
||||
{
|
||||
protocol = "https";
|
||||
}
|
||||
std::string resource;
|
||||
if (Resource == BlobSasResource::Container)
|
||||
{
|
||||
resource = "c";
|
||||
}
|
||||
else if (Resource == BlobSasResource::Blob)
|
||||
{
|
||||
resource = "b";
|
||||
}
|
||||
else if (Resource == BlobSasResource::BlobSnapshot)
|
||||
{
|
||||
resource = "bs";
|
||||
}
|
||||
else if (Resource == BlobSasResource::BlobVersion)
|
||||
{
|
||||
resource = "bv";
|
||||
}
|
||||
std::string stringToSign = Permissions + "\n" + StartsOn + "\n" + ExpiresOn + "\n"
|
||||
+ canonicalName + "\n" + Identifier + "\n" + (IPRange.HasValue() ? IPRange.GetValue() : "")
|
||||
+ "\n" + protocol + "\n" + Version + "\n" + resource + "\n" + Snapshot + "\n" + CacheControl
|
||||
+ "\n" + ContentDisposition + "\n" + ContentEncoding + "\n" + ContentLanguage + "\n"
|
||||
+ ContentType;
|
||||
|
||||
std::string signature
|
||||
= Base64Encode(HMAC_SHA256(stringToSign, Base64Decode(credential.GetAccountKey())));
|
||||
|
||||
UriBuilder builder;
|
||||
builder.AppendQuery("sv", Version);
|
||||
builder.AppendQuery("spr", protocol);
|
||||
builder.AppendQuery("st", StartsOn);
|
||||
builder.AppendQuery("se", ExpiresOn);
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
builder.AppendQuery("sip", IPRange.GetValue());
|
||||
}
|
||||
if (!Identifier.empty())
|
||||
{
|
||||
builder.AppendQuery("si", Identifier);
|
||||
}
|
||||
builder.AppendQuery("sr", resource);
|
||||
builder.AppendQuery("sp", Permissions);
|
||||
builder.AppendQuery("sig", signature, true);
|
||||
if (!CacheControl.empty())
|
||||
{
|
||||
builder.AppendQuery("rscc", CacheControl);
|
||||
}
|
||||
if (!ContentDisposition.empty())
|
||||
{
|
||||
builder.AppendQuery("rscd", ContentDisposition);
|
||||
}
|
||||
if (!ContentEncoding.empty())
|
||||
{
|
||||
builder.AppendQuery("rsce", ContentEncoding);
|
||||
}
|
||||
if (!ContentLanguage.empty())
|
||||
{
|
||||
builder.AppendQuery("rscl", ContentLanguage);
|
||||
}
|
||||
if (!ContentType.empty())
|
||||
{
|
||||
builder.AppendQuery("rsct", ContentType);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
std::string BlobSasBuilder::ToSasQueryParameters(
|
||||
const UserDelegationKey& userDelegationKey,
|
||||
const std::string& accountName)
|
||||
{
|
||||
unused(userDelegationKey, accountName);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Blobs
|
||||
127
sdk/storage/src/common/account_sas_builder.cpp
Normal file
127
sdk/storage/src/common/account_sas_builder.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "common/account_sas_builder.hpp"
|
||||
#include "common/crypt.hpp"
|
||||
#include "common/storage_uri_builder.hpp"
|
||||
|
||||
namespace Azure { namespace Storage {
|
||||
|
||||
void AccountSasBuilder::SetPermissions(AccountSasPermissions permissions)
|
||||
{
|
||||
Permissions.clear();
|
||||
if ((permissions & AccountSasPermissions::Read) == AccountSasPermissions::Read)
|
||||
{
|
||||
Permissions += "r";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Write) == AccountSasPermissions::Write)
|
||||
{
|
||||
Permissions += "w";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Delete) == AccountSasPermissions::Delete)
|
||||
{
|
||||
Permissions += "d";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::DeleteVersion)
|
||||
== AccountSasPermissions::DeleteVersion)
|
||||
{
|
||||
Permissions += "x";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::List) == AccountSasPermissions::List)
|
||||
{
|
||||
Permissions += "l";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Add) == AccountSasPermissions::Add)
|
||||
{
|
||||
Permissions += "a";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Create) == AccountSasPermissions::Create)
|
||||
{
|
||||
Permissions += "c";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Update) == AccountSasPermissions::Update)
|
||||
{
|
||||
Permissions += "u";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Process) == AccountSasPermissions::Process)
|
||||
{
|
||||
Permissions += "p";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Tags) == AccountSasPermissions::Tags)
|
||||
{
|
||||
Permissions += "t";
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Filter) == AccountSasPermissions::Filter)
|
||||
{
|
||||
Permissions += "f";
|
||||
}
|
||||
}
|
||||
|
||||
std::string AccountSasBuilder::ToSasQueryParameters(const SharedKeyCredential& credential)
|
||||
{
|
||||
std::string protocol;
|
||||
if (Protocol == SasProtocol::HttpsAndHtttp)
|
||||
{
|
||||
protocol = "https,http";
|
||||
}
|
||||
else
|
||||
{
|
||||
protocol = "https";
|
||||
}
|
||||
std::string services;
|
||||
if ((Services & AccountSasServices::Blobs) == AccountSasServices::Blobs)
|
||||
{
|
||||
services += "b";
|
||||
}
|
||||
if ((Services & AccountSasServices::Queue) == AccountSasServices::Queue)
|
||||
{
|
||||
services += "q";
|
||||
}
|
||||
if ((Services & AccountSasServices::Files) == AccountSasServices::Files)
|
||||
{
|
||||
services += "f";
|
||||
}
|
||||
|
||||
std::string resourceTypes;
|
||||
if ((ResourceTypes & AccountSasResource::Service) == AccountSasResource::Service)
|
||||
{
|
||||
resourceTypes += "s";
|
||||
}
|
||||
if ((ResourceTypes & AccountSasResource::Container) == AccountSasResource::Container)
|
||||
{
|
||||
resourceTypes += "c";
|
||||
}
|
||||
if ((ResourceTypes & AccountSasResource::Object) == AccountSasResource::Object)
|
||||
{
|
||||
resourceTypes += "o";
|
||||
}
|
||||
|
||||
std::string stringToSign = credential.AccountName + "\n" + Permissions + "\n" + services + "\n"
|
||||
+ resourceTypes + "\n" + (StartsOn.HasValue() ? StartsOn.GetValue() : "") + "\n" + ExpiresOn
|
||||
+ "\n" + (IPRange.HasValue() ? IPRange.GetValue() : "") + "\n" + protocol + "\n" + Version
|
||||
+ "\n";
|
||||
|
||||
std::string signature
|
||||
= Base64Encode(HMAC_SHA256(stringToSign, Base64Decode(credential.GetAccountKey())));
|
||||
|
||||
UriBuilder builder;
|
||||
builder.AppendQuery("sv", Version);
|
||||
builder.AppendQuery("ss", services);
|
||||
builder.AppendQuery("srt", resourceTypes);
|
||||
builder.AppendQuery("sp", Permissions);
|
||||
if (StartsOn.HasValue())
|
||||
{
|
||||
builder.AppendQuery("st", StartsOn.GetValue());
|
||||
}
|
||||
builder.AppendQuery("se", ExpiresOn);
|
||||
if (IPRange.HasValue())
|
||||
{
|
||||
builder.AppendQuery("sip", IPRange.GetValue());
|
||||
}
|
||||
builder.AppendQuery("spr", protocol);
|
||||
builder.AppendQuery("sig", signature, true);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
}} // namespace Azure::Storage
|
||||
@ -190,7 +190,6 @@ namespace Azure { namespace Storage {
|
||||
std::string full_url;
|
||||
if (!m_scheme.empty())
|
||||
{
|
||||
|
||||
full_url += m_scheme + "://";
|
||||
}
|
||||
full_url += m_host;
|
||||
|
||||
@ -16,6 +16,7 @@ add_executable (
|
||||
blobs/append_blob_client_test.cpp
|
||||
blobs/page_blob_client_test.hpp
|
||||
blobs/page_blob_client_test.cpp
|
||||
blobs/blob_sas_test.cpp
|
||||
blobs/performance_benchmark.cpp
|
||||
blobs/large_scale_test.cpp
|
||||
datalake/service_client_test.hpp
|
||||
|
||||
406
sdk/storage/test/blobs/blob_sas_test.cpp
Normal file
406
sdk/storage/test/blobs/blob_sas_test.cpp
Normal file
@ -0,0 +1,406 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "blob_container_client_test.hpp"
|
||||
#include "blobs/blob_sas_builder.hpp"
|
||||
|
||||
namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
TEST_F(BlobContainerClientTest, BlobSasTest)
|
||||
{
|
||||
AccountSasBuilder accountSasBuilder;
|
||||
accountSasBuilder.Protocol = SasProtocol::HttpsAndHtttp;
|
||||
accountSasBuilder.StartsOn
|
||||
= ToISO8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
accountSasBuilder.ExpiresOn
|
||||
= ToISO8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
accountSasBuilder.Services = AccountSasServices::Blobs;
|
||||
accountSasBuilder.ResourceTypes = AccountSasResource::Object | AccountSasResource::Container;
|
||||
|
||||
std::string blobName = RandomString();
|
||||
Blobs::BlobSasBuilder blobSasBuilder;
|
||||
blobSasBuilder.Protocol = SasProtocol::HttpsAndHtttp;
|
||||
blobSasBuilder.StartsOn = ToISO8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
blobSasBuilder.ExpiresOn
|
||||
= ToISO8601(std::chrono::system_clock::now() + std::chrono::minutes(60));
|
||||
blobSasBuilder.ContainerName = m_containerName;
|
||||
blobSasBuilder.BlobName = blobName;
|
||||
blobSasBuilder.Resource = Blobs::BlobSasResource::Blob;
|
||||
|
||||
Blobs::BlobSasBuilder containerSasBuilder = blobSasBuilder;
|
||||
containerSasBuilder.BlobName.clear();
|
||||
containerSasBuilder.Resource = Blobs::BlobSasResource::Container;
|
||||
|
||||
auto keyCredential
|
||||
= Details::ParseConnectionString(StandardStorageConnectionString()).KeyCredential;
|
||||
auto blobServiceClient0
|
||||
= Blobs::BlobServiceClient::CreateFromConnectionString(StandardStorageConnectionString());
|
||||
auto blobContainerClient0 = blobServiceClient0.GetBlobContainerClient(m_containerName);
|
||||
auto blobClient0 = blobContainerClient0.GetAppendBlobClient(blobName);
|
||||
|
||||
auto serviceUri = blobServiceClient0.GetUri();
|
||||
auto containerUri = blobContainerClient0.GetUri();
|
||||
auto blobUri = blobClient0.GetUri();
|
||||
|
||||
auto verify_blob_read = [&](const std::string& sas) {
|
||||
EXPECT_NO_THROW(blobClient0.Create());
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sas);
|
||||
auto downloadedContent = blobClient.Download();
|
||||
EXPECT_TRUE(ReadBodyStream(downloadedContent->BodyStream).empty());
|
||||
};
|
||||
|
||||
auto verify_blob_write = [&](const std::string& sas) {
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sas);
|
||||
EXPECT_NO_THROW(blobClient.Create());
|
||||
};
|
||||
|
||||
auto verify_blob_delete = [&](const std::string& sas) {
|
||||
blobClient0.Create();
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sas);
|
||||
EXPECT_NO_THROW(blobClient.Delete());
|
||||
};
|
||||
|
||||
auto verify_blob_add = [&](const std::string& sas) {
|
||||
blobClient0.Create();
|
||||
std::string content = "Hello world";
|
||||
auto blockContent = Azure::Core::Http::MemoryBodyStream(
|
||||
reinterpret_cast<const uint8_t*>(content.data()), content.size());
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sas);
|
||||
EXPECT_NO_THROW(blobClient.AppendBlock(&blockContent));
|
||||
};
|
||||
|
||||
auto verify_blob_list = [&](const std::string& sas) {
|
||||
auto blobContainerClient = Blobs::BlobContainerClient(containerUri + sas);
|
||||
EXPECT_NO_THROW(blobContainerClient.ListBlobsFlat());
|
||||
};
|
||||
|
||||
auto verify_blob_create = [&](const std::string& sas) {
|
||||
try
|
||||
{
|
||||
blobClient0.Delete();
|
||||
}
|
||||
catch (StorageError&)
|
||||
{
|
||||
}
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sas);
|
||||
blobClient.Create();
|
||||
blobClient.CreateSnapshot();
|
||||
Blobs::DeleteBlobOptions options;
|
||||
options.DeleteSnapshots = Blobs::DeleteSnapshotsOption::IncludeSnapshots;
|
||||
blobClient0.Delete(options);
|
||||
};
|
||||
|
||||
auto verify_blob_tags = [&](const std::string& sas) {
|
||||
unused(sas);
|
||||
// TODO: Add test for blob tags
|
||||
};
|
||||
|
||||
auto verify_blob_filter = [&](const std::string& sas) {
|
||||
unused(sas);
|
||||
// TODO: Add test for blob tags
|
||||
};
|
||||
|
||||
auto verify_blob_delete_version = [&](const std::string& sas) {
|
||||
unused(sas);
|
||||
// TODO: Add test for versions
|
||||
};
|
||||
|
||||
for (auto permissions : {
|
||||
AccountSasPermissions::All,
|
||||
AccountSasPermissions::Read,
|
||||
AccountSasPermissions::Write,
|
||||
AccountSasPermissions::Delete,
|
||||
AccountSasPermissions::DeleteVersion,
|
||||
AccountSasPermissions::List,
|
||||
AccountSasPermissions::Add,
|
||||
AccountSasPermissions::Create,
|
||||
AccountSasPermissions::Tags,
|
||||
AccountSasPermissions::Filter,
|
||||
})
|
||||
{
|
||||
accountSasBuilder.SetPermissions(permissions);
|
||||
auto sasToken = accountSasBuilder.ToSasQueryParameters(*keyCredential);
|
||||
|
||||
if ((permissions & AccountSasPermissions::Read) == AccountSasPermissions::Read)
|
||||
{
|
||||
verify_blob_read(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Write) == AccountSasPermissions::Write)
|
||||
{
|
||||
verify_blob_write(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Delete) == AccountSasPermissions::Delete)
|
||||
{
|
||||
verify_blob_delete(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::DeleteVersion)
|
||||
== AccountSasPermissions::DeleteVersion)
|
||||
{
|
||||
verify_blob_delete_version(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::List) == AccountSasPermissions::List)
|
||||
{
|
||||
verify_blob_list(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Add) == AccountSasPermissions::Add)
|
||||
{
|
||||
verify_blob_add(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Create) == AccountSasPermissions::Create)
|
||||
{
|
||||
verify_blob_create(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Tags) == AccountSasPermissions::Tags)
|
||||
{
|
||||
verify_blob_tags(sasToken);
|
||||
}
|
||||
if ((permissions & AccountSasPermissions::Filter) == AccountSasPermissions::Filter)
|
||||
{
|
||||
verify_blob_filter(sasToken);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto permissions :
|
||||
{Blobs::BlobSasPermissions::All,
|
||||
Blobs::BlobSasPermissions::Read,
|
||||
Blobs::BlobSasPermissions::Write,
|
||||
Blobs::BlobSasPermissions::Delete,
|
||||
Blobs::BlobSasPermissions::Add,
|
||||
Blobs::BlobSasPermissions::Create,
|
||||
Blobs::BlobSasPermissions::Tags,
|
||||
Blobs::BlobSasPermissions::DeleteVersion})
|
||||
{
|
||||
blobSasBuilder.SetPermissions(permissions);
|
||||
auto sasToken = blobSasBuilder.ToSasQueryParameters(*keyCredential);
|
||||
|
||||
if ((permissions & Blobs::BlobSasPermissions::Read) == Blobs::BlobSasPermissions::Read)
|
||||
{
|
||||
verify_blob_read(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobSasPermissions::Write) == Blobs::BlobSasPermissions::Write)
|
||||
{
|
||||
verify_blob_write(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobSasPermissions::Delete) == Blobs::BlobSasPermissions::Delete)
|
||||
{
|
||||
verify_blob_delete(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobSasPermissions::Add) == Blobs::BlobSasPermissions::Add)
|
||||
{
|
||||
verify_blob_add(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobSasPermissions::Create) == Blobs::BlobSasPermissions::Create)
|
||||
{
|
||||
verify_blob_create(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobSasPermissions::Tags) == Blobs::BlobSasPermissions::Tags)
|
||||
{
|
||||
verify_blob_tags(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobSasPermissions::DeleteVersion)
|
||||
== Blobs::BlobSasPermissions::DeleteVersion)
|
||||
{
|
||||
verify_blob_delete_version(sasToken);
|
||||
}
|
||||
}
|
||||
|
||||
// Expires
|
||||
{
|
||||
AccountSasBuilder builder2 = accountSasBuilder;
|
||||
builder2.SetPermissions(AccountSasPermissions::All);
|
||||
builder2.StartsOn = ToISO8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
builder2.ExpiresOn = ToISO8601(std::chrono::system_clock::now() - std::chrono::minutes(1));
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), std::runtime_error);
|
||||
}
|
||||
|
||||
// Without start time
|
||||
{
|
||||
AccountSasBuilder builder2 = accountSasBuilder;
|
||||
builder2.SetPermissions(AccountSasPermissions::All);
|
||||
builder2.StartsOn.Reset();
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
EXPECT_NO_THROW(verify_blob_create(sasToken));
|
||||
}
|
||||
|
||||
// IP
|
||||
{
|
||||
AccountSasBuilder builder2 = accountSasBuilder;
|
||||
builder2.SetPermissions(AccountSasPermissions::All);
|
||||
builder2.IPRange = "1.1.1.1";
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), std::runtime_error);
|
||||
builder2.IPRange = "0.0.0.0-255.255.255.255";
|
||||
sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
EXPECT_NO_THROW(verify_blob_create(sasToken));
|
||||
}
|
||||
|
||||
// Account SAS Service
|
||||
{
|
||||
AccountSasBuilder builder2 = accountSasBuilder;
|
||||
builder2.SetPermissions(AccountSasPermissions::All);
|
||||
builder2.Services = AccountSasServices::Files;
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), std::runtime_error);
|
||||
|
||||
builder2.Services = AccountSasServices::All;
|
||||
sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
EXPECT_NO_THROW(verify_blob_create(sasToken));
|
||||
}
|
||||
|
||||
// Account SAS Resource Types
|
||||
{
|
||||
AccountSasBuilder builder2 = accountSasBuilder;
|
||||
builder2.SetPermissions(AccountSasPermissions::All);
|
||||
builder2.ResourceTypes = AccountSasResource::Service;
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), std::runtime_error);
|
||||
|
||||
auto serviceClient = Blobs::BlobServiceClient(serviceUri + sasToken);
|
||||
EXPECT_NO_THROW(serviceClient.ListBlobContainersSegment());
|
||||
}
|
||||
|
||||
for (auto permissions :
|
||||
{Blobs::BlobContainerSasPermissions::All,
|
||||
Blobs::BlobContainerSasPermissions::Read,
|
||||
Blobs::BlobContainerSasPermissions::Write,
|
||||
Blobs::BlobContainerSasPermissions::Delete,
|
||||
Blobs::BlobContainerSasPermissions::List,
|
||||
Blobs::BlobContainerSasPermissions::Add,
|
||||
Blobs::BlobContainerSasPermissions::Create,
|
||||
Blobs::BlobContainerSasPermissions::Tags})
|
||||
{
|
||||
containerSasBuilder.SetPermissions(permissions);
|
||||
auto sasToken = containerSasBuilder.ToSasQueryParameters(*keyCredential);
|
||||
if ((permissions & Blobs::BlobContainerSasPermissions::Read)
|
||||
== Blobs::BlobContainerSasPermissions::Read)
|
||||
{
|
||||
verify_blob_read(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobContainerSasPermissions::Write)
|
||||
== Blobs::BlobContainerSasPermissions::Write)
|
||||
{
|
||||
verify_blob_write(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobContainerSasPermissions::Delete)
|
||||
== Blobs::BlobContainerSasPermissions::Delete)
|
||||
{
|
||||
verify_blob_delete(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobContainerSasPermissions::List)
|
||||
== Blobs::BlobContainerSasPermissions::List)
|
||||
{
|
||||
verify_blob_list(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobContainerSasPermissions::Add)
|
||||
== Blobs::BlobContainerSasPermissions::Add)
|
||||
{
|
||||
verify_blob_add(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobContainerSasPermissions::Create)
|
||||
== Blobs::BlobContainerSasPermissions::Create)
|
||||
{
|
||||
verify_blob_create(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobContainerSasPermissions::Tags)
|
||||
== Blobs::BlobContainerSasPermissions::Tags)
|
||||
{
|
||||
verify_blob_tags(sasToken);
|
||||
}
|
||||
}
|
||||
|
||||
blobSasBuilder.SetPermissions(Blobs::BlobSasPermissions::All);
|
||||
// Expires
|
||||
{
|
||||
Blobs::BlobSasBuilder builder2 = blobSasBuilder;
|
||||
builder2.StartsOn = ToISO8601(std::chrono::system_clock::now() - std::chrono::minutes(5));
|
||||
builder2.ExpiresOn = ToISO8601(std::chrono::system_clock::now() - std::chrono::minutes(1));
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), std::runtime_error);
|
||||
}
|
||||
|
||||
// IP
|
||||
{
|
||||
Blobs::BlobSasBuilder builder2 = blobSasBuilder;
|
||||
builder2.IPRange = "0.0.0.0-0.0.0.1";
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
EXPECT_THROW(verify_blob_create(sasToken), std::runtime_error);
|
||||
builder2.IPRange = "0.0.0.0-255.255.255.255";
|
||||
sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
EXPECT_NO_THROW(verify_blob_create(sasToken));
|
||||
}
|
||||
|
||||
// response headers override
|
||||
{
|
||||
Blobs::BlobHttpHeaders headers;
|
||||
headers.ContentType = "application/x-binary";
|
||||
headers.ContentLanguage = "en-US";
|
||||
headers.ContentDisposition = "attachment";
|
||||
headers.CacheControl = "no-cache";
|
||||
headers.ContentEncoding = "identify";
|
||||
|
||||
Blobs::BlobSasBuilder builder2 = blobSasBuilder;
|
||||
builder2.ContentType = "application/x-binary";
|
||||
builder2.ContentLanguage = "en-US";
|
||||
builder2.ContentDisposition = "attachment";
|
||||
builder2.CacheControl = "no-cache";
|
||||
builder2.ContentEncoding = "identify";
|
||||
auto sasToken = builder2.ToSasQueryParameters(*keyCredential);
|
||||
auto blobClient = Blobs::AppendBlobClient(blobUri + sasToken);
|
||||
blobClient0.Create();
|
||||
auto p = blobClient.GetProperties();
|
||||
EXPECT_EQ(p->HttpHeaders.ContentType, headers.ContentType);
|
||||
EXPECT_EQ(p->HttpHeaders.ContentLanguage, headers.ContentLanguage);
|
||||
EXPECT_EQ(p->HttpHeaders.ContentDisposition, headers.ContentDisposition);
|
||||
EXPECT_EQ(p->HttpHeaders.CacheControl, headers.CacheControl);
|
||||
EXPECT_EQ(p->HttpHeaders.ContentEncoding, headers.ContentEncoding);
|
||||
}
|
||||
|
||||
blobClient0.Create();
|
||||
Blobs::BlobSasBuilder BlobSnapshotSasBuilder = blobSasBuilder;
|
||||
BlobSnapshotSasBuilder.Resource = Blobs::BlobSasResource::BlobSnapshot;
|
||||
|
||||
std::string blobSnapshotUri;
|
||||
|
||||
auto verify_blob_snapshot_read = [&](const std::string sas) {
|
||||
auto blobSnapshotClient = Blobs::AppendBlobClient(blobSnapshotUri + "&" + sas.substr(1));
|
||||
auto downloadedContent = blobSnapshotClient.Download();
|
||||
EXPECT_TRUE(ReadBodyStream(downloadedContent->BodyStream).empty());
|
||||
};
|
||||
|
||||
auto verify_blob_snapshot_delete = [&](const std::string sas) {
|
||||
auto blobSnapshotClient = Blobs::AppendBlobClient(blobSnapshotUri + "&" + sas.substr(1));
|
||||
EXPECT_NO_THROW(blobSnapshotClient.Delete());
|
||||
};
|
||||
|
||||
for (auto permissions : {
|
||||
Blobs::BlobSasPermissions::Read | Blobs::BlobSasPermissions::Delete,
|
||||
Blobs::BlobSasPermissions::Read,
|
||||
Blobs::BlobSasPermissions::Delete,
|
||||
})
|
||||
{
|
||||
std::string snapshot = blobClient0.CreateSnapshot()->Snapshot;
|
||||
BlobSnapshotSasBuilder.Snapshot = snapshot;
|
||||
blobSnapshotUri = blobClient0.WithSnapshot(snapshot).GetUri();
|
||||
BlobSnapshotSasBuilder.SetPermissions(permissions);
|
||||
auto sasToken = BlobSnapshotSasBuilder.ToSasQueryParameters(*keyCredential);
|
||||
|
||||
if ((permissions & Blobs::BlobSasPermissions::Read) == Blobs::BlobSasPermissions::Read)
|
||||
{
|
||||
verify_blob_snapshot_read(sasToken);
|
||||
}
|
||||
if ((permissions & Blobs::BlobSasPermissions::Delete) == Blobs::BlobSasPermissions::Delete)
|
||||
{
|
||||
verify_blob_snapshot_delete(sasToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
@ -11,8 +11,11 @@
|
||||
#include <cctype>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
namespace Azure { namespace Storage { namespace Test {
|
||||
@ -214,4 +217,33 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ToISO8601(const std::chrono::system_clock::time_point& time_point)
|
||||
{
|
||||
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(time_point);
|
||||
struct tm ct;
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&ct, &epoch_seconds);
|
||||
#else
|
||||
gmtime_r(&epoch_seconds, &ct);
|
||||
#endif
|
||||
char buff[64];
|
||||
std::strftime(buff, sizeof(buff), "%Y-%m-%dT%H:%M:%SZ", &ct);
|
||||
return std::string(buff);
|
||||
}
|
||||
|
||||
std::string ToRFC1123(const std::chrono::system_clock::time_point& time_point)
|
||||
{
|
||||
std::time_t epoch_seconds = std::chrono::system_clock::to_time_t(time_point);
|
||||
struct tm ct;
|
||||
#ifdef _WIN32
|
||||
gmtime_s(&ct, &epoch_seconds);
|
||||
#else
|
||||
gmtime_r(&epoch_seconds, &ct);
|
||||
#endif
|
||||
std::stringstream ss;
|
||||
ss.imbue(std::locale("C"));
|
||||
ss << std::put_time(&ct, "%a, %d %b %Y %H:%M:%S GMT");
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
const std::string& StandardStorageConnectionString();
|
||||
@ -59,4 +61,7 @@ namespace Azure { namespace Storage { namespace Test {
|
||||
|
||||
void DeleteFile(const std::string& filename);
|
||||
|
||||
std::string ToISO8601(const std::chrono::system_clock::time_point& time_point);
|
||||
std::string ToRFC1123(const std::chrono::system_clock::time_point& time_point);
|
||||
|
||||
}}} // namespace Azure::Storage::Test
|
||||
|
||||
Loading…
Reference in New Issue
Block a user