diff --git a/Microsoft.WindowsAzure.Storage/includes/was/core.h b/Microsoft.WindowsAzure.Storage/includes/was/core.h index 7e4d446a..3c516a61 100644 --- a/Microsoft.WindowsAzure.Storage/includes/was/core.h +++ b/Microsoft.WindowsAzure.Storage/includes/was/core.h @@ -212,13 +212,28 @@ namespace azure { namespace storage { { } + class account_key_credential + { + public: + account_key_credential(std::vector account_key = std::vector()) : m_account_key(std::move(account_key)) + { + } + + public: + std::vector m_account_key; + + private: + pplx::extensibility::reader_writer_lock_t m_mutex; + + friend class storage_credentials; + }; + /// /// Initializes a new instance of the class with the specified account name and key value. /// /// A string containing the name of the storage account. /// A string containing the Base64-encoded account access key. - storage_credentials(utility::string_t account_name, const utility::string_t& account_key) - : m_account_name(std::move(account_name)), m_account_key(utility::conversions::from_base64(account_key)) + storage_credentials(utility::string_t account_name, const utility::string_t& account_key) : m_account_name(std::move(account_name)), m_account_key_credential(std::make_shared(utility::conversions::from_base64(account_key))) { } @@ -227,8 +242,7 @@ namespace azure { namespace storage { /// /// A string containing the name of the storage account. /// An array of bytes that represent the account access key. - storage_credentials(utility::string_t account_name, std::vector account_key) - : m_account_name(std::move(account_name)), m_account_key(std::move(account_key)) + storage_credentials(utility::string_t account_name, std::vector account_key) : m_account_name(std::move(account_name)), m_account_key_credential(std::make_shared(std::move(account_key))) { } @@ -339,9 +353,10 @@ namespace azure { namespace storage { m_sas_token = std::forward(other).m_sas_token; m_sas_token_with_api_version = std::forward(other).m_sas_token_with_api_version; m_account_name = std::forward(other).m_account_name; - m_account_key = std::forward(other).m_account_key; + std::atomic_store_explicit(&m_account_key_credential, std::atomic_load_explicit(&other.m_account_key_credential, std::memory_order_acquire), std::memory_order_release); + auto key_ptr = std::forward(other).m_account_key_credential; std::atomic_store_explicit(&m_bearer_token_credential, std::atomic_load_explicit(&other.m_bearer_token_credential, std::memory_order_acquire), std::memory_order_release); - auto ptr = std::forward(other).m_bearer_token_credential; + auto token_ptr = std::forward(other).m_bearer_token_credential; } return *this; } @@ -387,7 +402,43 @@ namespace azure { namespace storage { /// An array of bytes that contains the key. const std::vector& account_key() const { - return m_account_key; + auto account_key_ptr = std::atomic_load_explicit(&m_account_key_credential, std::memory_order_acquire); + pplx::extensibility::scoped_read_lock_t guard(account_key_ptr->m_mutex); + return account_key_ptr->m_account_key; + } + + /// + /// Sets the account key for the credentials. + /// + /// A string containing the Base64-encoded account access key. + void set_account_key(const utility::string_t& account_key) + { + set_account_key(utility::conversions::from_base64(account_key)); + } + + /// + /// Sets the account key for the credentials. + /// + /// An array of bytes that represent the account access key. + void set_account_key(std::vector account_key) + { + auto account_key_ptr = std::atomic_load_explicit(&m_account_key_credential, std::memory_order_acquire); + if (!account_key_ptr) + { + auto new_credential = std::make_shared(); + new_credential->m_account_key = std::move(account_key); + /* Compares m_account_key_credential and account_key_ptr(nullptr). + * If they are equivalent, assigns new_credential into m_account_key_credential and returns true. + * If they are not equivalent, assigns m_account_key_credential into m_account_key and returns false. + */ + bool set = std::atomic_compare_exchange_strong_explicit(&m_account_key_credential, &account_key_ptr, new_credential, std::memory_order_release, std::memory_order_acquire); + if (set) { + return; + } + account_key = std::move(new_credential->m_account_key); + } + pplx::extensibility::scoped_rw_lock_t guard(account_key_ptr->m_mutex); + account_key_ptr->m_account_key = std::move(account_key); } /// @@ -432,7 +483,7 @@ namespace azure { namespace storage { /// true if the credentials are for anonymous access; otherwise, false. bool is_anonymous() const { - return m_sas_token.empty() && m_account_key.empty() && !is_bearer_token(); + return m_sas_token.empty() && !is_account_key() && !is_bearer_token(); } /// @@ -441,7 +492,7 @@ namespace azure { namespace storage { /// true if the credentials are a shared access signature token; otherwise, false. bool is_sas() const { - return !m_sas_token.empty() && m_account_key.empty() && !is_bearer_token(); + return !m_sas_token.empty() && !is_account_key() && !is_bearer_token(); } /// @@ -450,7 +501,7 @@ namespace azure { namespace storage { /// true if the credentials are a shared key; otherwise, false. bool is_shared_key() const { - return m_sas_token.empty() && !m_account_key.empty() && !is_bearer_token(); + return m_sas_token.empty() && is_account_key() && !is_bearer_token(); } /// @@ -467,14 +518,28 @@ namespace azure { namespace storage { return !token_ptr->m_bearer_token.empty(); } + /// + /// Indicates whether the credentials are an account key. + /// + /// true if the credentials are an account key; otherwise false. + bool is_account_key() const { + auto account_key_ptr = std::atomic_load_explicit(&m_account_key_credential, std::memory_order_acquire); + if (!account_key_ptr) + { + return false; + } + pplx::extensibility::scoped_read_lock_t guard(account_key_ptr->m_mutex); + return !account_key_ptr->m_account_key.empty(); + } + private: utility::string_t m_sas_token; utility::string_t m_sas_token_with_api_version; utility::string_t m_account_name; - std::vector m_account_key; // We use std::atomic_{load/store/...} functions specialized for std::shared_ptr to access this member, since std::atomic> is not available until C++20. // These become deprecated since C++20, but still compile. + std::shared_ptr m_account_key_credential; std::shared_ptr m_bearer_token_credential; }; diff --git a/Microsoft.WindowsAzure.Storage/tests/cloud_storage_account_test.cpp b/Microsoft.WindowsAzure.Storage/tests/cloud_storage_account_test.cpp index ce7b30af..e5e73ab3 100644 --- a/Microsoft.WindowsAzure.Storage/tests/cloud_storage_account_test.cpp +++ b/Microsoft.WindowsAzure.Storage/tests/cloud_storage_account_test.cpp @@ -42,7 +42,9 @@ void check_credentials_equal(const azure::storage::storage_credentials& a, const CHECK_EQUAL(a.is_sas(), b.is_sas()); CHECK_EQUAL(a.is_shared_key(), b.is_shared_key()); CHECK_UTF8_EQUAL(a.account_name(), b.account_name()); - CHECK_UTF8_EQUAL(utility::conversions::to_base64(a.account_key()), utility::conversions::to_base64(b.account_key())); + if (a.is_shared_key() && b.is_shared_key()) { + CHECK_UTF8_EQUAL(utility::conversions::to_base64(a.account_key()), utility::conversions::to_base64(b.account_key())); + } } void check_account_equal(azure::storage::cloud_storage_account& a, azure::storage::cloud_storage_account& b) @@ -487,7 +489,7 @@ SUITE(Core) CHECK_UTF8_EQUAL(token, creds.sas_token()); CHECK(creds.account_name().empty()); - CHECK(creds.account_key().empty()); + CHECK(!creds.is_account_key()); CHECK(!creds.is_anonymous()); CHECK(creds.is_sas()); CHECK(!creds.is_shared_key()); @@ -502,7 +504,7 @@ SUITE(Core) CHECK_UTF8_EQUAL(token, creds.sas_token()); CHECK(creds.account_name().empty()); - CHECK(creds.account_key().empty()); + CHECK(!creds.is_account_key()); CHECK(!creds.is_anonymous()); CHECK(creds.is_sas()); CHECK(!creds.is_shared_key());