diff --git a/sdk/storage/azure-storage-files-datalake/CHANGELOG.md b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md index 72d620a6f..4aeabd4f5 100644 --- a/sdk/storage/azure-storage-files-datalake/CHANGELOG.md +++ b/sdk/storage/azure-storage-files-datalake/CHANGELOG.md @@ -5,6 +5,7 @@ ### New Features - Added `Owner`, `Permissions`, and `Group` to `GetDataLakePathAccessControlResult`. +- Added support for `GetAccessPolicy` and `SetAccessPolicy` in `DataLakeFileSystemClient`. ### Breaking Changes diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_system_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_system_client.hpp index b83360704..f1c4fa34f 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_system_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_file_system_client.hpp @@ -177,6 +177,31 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { bool recursive, const ListPathsSinglePageOptions& options = ListPathsSinglePageOptions()) const; + /** + * @brief Gets the permissions for this file system. The permissions indicate whether + * file system data may be accessed publicly. + * + * @param options Optional parameters to execute this function. + * @return A GetDataLakeFileSystemAccessPolicyResult describing the container's access policy. + * @remark This request is sent to blob endpoint. + */ + Azure::Core::Response GetAccessPolicy( + const GetDataLakeFileSystemAccessPolicyOptions& options + = GetDataLakeFileSystemAccessPolicyOptions()) const; + + /** + * @brief Sets the permissions for the specified file system. The permissions indicate + * whether file system's data may be accessed publicly. + * + * @param options Optional + * parameters to execute this function. + * @return A SetDataLakeFileSystemAccessPolicyResult describing the updated file system. + * @remark This request is sent to blob endpoint. + */ + Azure::Core::Response SetAccessPolicy( + const SetDataLakeFileSystemAccessPolicyOptions& options + = SetDataLakeFileSystemAccessPolicyOptions()) const; + private: Azure::Core::Http::Url m_dfsUrl; Blobs::BlobContainerClient m_blobContainerClient; diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp index 5d2ff4692..76ff928c0 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_options.hpp @@ -12,6 +12,7 @@ #include #include +#include "azure/storage/files/datalake/datalake_responses.hpp" #include "azure/storage/files/datalake/protocol/datalake_rest_client.hpp" namespace Azure { namespace Storage { namespace Files { namespace DataLake { @@ -208,6 +209,50 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { Azure::Core::Nullable Directory; }; + /** + * @brief Optional parameters for FileSystemClient::GetAccessPolicy. + */ + struct GetDataLakeFileSystemAccessPolicyOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief Optional conditions that must be met to perform this operation. + */ + LeaseAccessConditions AccessConditions; + }; + + /** + * @brief Optional parameters for FileSystemClient::SetAccessPolicy. + */ + struct SetDataLakeFileSystemAccessPolicyOptions + { + /** + * @brief Context for cancelling long running operations. + */ + Azure::Core::Context Context; + + /** + * @brief Specifies whether data in the file system may be accessed publicly and the level + * of access. + */ + Models::PublicAccessType AccessType = Models::PublicAccessType::None; + + /** + * @brief Stored access policies that you can use to provide fine grained control over + * file system permissions. + */ + std::vector SignedIdentifiers; + + /** + * @brief Optional conditions that must be met to perform this operation. + */ + FileSystemAccessConditions AccessConditions; + }; + /** * @brief Optional parameters for PathClient::Append */ diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp index 5d8c3f2c1..2b44be0a9 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/datalake_responses.hpp @@ -22,6 +22,17 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam // FileSystemClient models: using ListPathsSinglePageResult = FileSystemListPathsResult; + using DataLakeSignedIdentifier = Blobs::Models::BlobSignedIdentifier; + + struct GetDataLakeFileSystemAccessPolicyResult + { + PublicAccessType AccessType = PublicAccessType::None; + std::string ETag; + Azure::Core::DateTime LastModified; + std::vector SignedIdentifiers; + }; // struct GetDataLakeFileSystemAccessPolicyResult + + using SetDataLakeFileSystemAccessPolicyResult = Blobs::Models::SetBlobContainerAccessPolicyResult; struct GetDataLakeFileSystemPropertiesResult { diff --git a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp index c595ab4ea..3fac36025 100644 --- a/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp +++ b/sdk/storage/azure-storage-files-datalake/inc/azure/storage/files/datalake/protocol/datalake_rest_client.hpp @@ -214,6 +214,22 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { std::vector Filesystems; }; + class PublicAccessType { + public: + PublicAccessType() = default; + explicit PublicAccessType(std::string value) : m_value(std::move(value)) {} + bool operator==(const PublicAccessType& other) const { return m_value == other.m_value; } + bool operator!=(const PublicAccessType& other) const { return !(*this == other); } + const std::string& Get() const { return m_value; } + + const static PublicAccessType FileSystem; + const static PublicAccessType Path; + const static PublicAccessType None; + + private: + std::string m_value; + }; // extensible enum PublicAccessType + // The value must be "account" for all account operations. class AccountResourceType { public: diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp index f463ff987..675ce1ba4 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_file_system_client.cpp @@ -304,4 +304,71 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { m_dfsUrl, *m_pipeline, options.Context, protocolLayerOptions); } + Azure::Core::Response + DataLakeFileSystemClient::GetAccessPolicy( + const GetDataLakeFileSystemAccessPolicyOptions& options) const + { + Blobs::GetBlobContainerAccessPolicyOptions blobOptions; + blobOptions.Context = options.Context; + blobOptions.AccessConditions.LeaseId = options.AccessConditions.LeaseId; + auto result = m_blobContainerClient.GetAccessPolicy(blobOptions); + Models::GetDataLakeFileSystemAccessPolicyResult ret; + if (result->AccessType == Blobs::Models::PublicAccessType::BlobContainer) + { + ret.AccessType = Models::PublicAccessType::FileSystem; + } + else if (result->AccessType == Blobs::Models::PublicAccessType::Blob) + { + ret.AccessType = Models::PublicAccessType::Path; + } + else if (result->AccessType == Blobs::Models::PublicAccessType::Private) + { + ret.AccessType = Models::PublicAccessType::None; + } + else + { + ret.AccessType = Models::PublicAccessType(result->AccessType.Get()); + } + ret.ETag = std::move(result->ETag); + ret.LastModified = std::move(result->LastModified); + ret.SignedIdentifiers = std::move(result->SignedIdentifiers); + return Azure::Core::Response( + std::move(ret), result.ExtractRawResponse()); + } + + Azure::Core::Response + DataLakeFileSystemClient::SetAccessPolicy( + const SetDataLakeFileSystemAccessPolicyOptions& options) const + { + Blobs::SetBlobContainerAccessPolicyOptions blobOptions; + blobOptions.Context = options.Context; + blobOptions.AccessConditions.IfModifiedSince = options.AccessConditions.IfModifiedSince; + blobOptions.AccessConditions.IfUnmodifiedSince = options.AccessConditions.IfUnmodifiedSince; + blobOptions.AccessConditions.LeaseId = options.AccessConditions.LeaseId; + blobOptions.SignedIdentifiers = options.SignedIdentifiers; + if (options.AccessType == Models::PublicAccessType::FileSystem) + { + blobOptions.AccessType = Blobs::Models::PublicAccessType::BlobContainer; + } + else if (options.AccessType == Models::PublicAccessType::Path) + { + blobOptions.AccessType = Blobs::Models::PublicAccessType::Blob; + } + else if (options.AccessType == Models::PublicAccessType::None) + { + blobOptions.AccessType = Blobs::Models::PublicAccessType::Private; + } + else + { + blobOptions.AccessType = Blobs::Models::PublicAccessType(options.AccessType.Get()); + } + auto result = m_blobContainerClient.SetAccessPolicy(blobOptions); + Models::SetDataLakeFileSystemAccessPolicyResult ret; + + ret.ETag = std::move(result->ETag); + ret.LastModified = std::move(result->LastModified); + return Azure::Core::Response( + std::move(ret), result.ExtractRawResponse()); + } + }}}} // namespace Azure::Storage::Files::DataLake diff --git a/sdk/storage/azure-storage-files-datalake/src/datalake_rest_client.cpp b/sdk/storage/azure-storage-files-datalake/src/datalake_rest_client.cpp index 80e6e6530..a501c6c48 100644 --- a/sdk/storage/azure-storage-files-datalake/src/datalake_rest_client.cpp +++ b/sdk/storage/azure-storage-files-datalake/src/datalake_rest_client.cpp @@ -16,6 +16,10 @@ namespace Azure { namespace Storage { namespace Files { namespace DataLake { nam const PathExpiryOptions PathExpiryOptions::RelativeToNow("RelativeToNow"); const PathExpiryOptions PathExpiryOptions::Absolute("Absolute"); + const PublicAccessType PublicAccessType::FileSystem("FileSystem"); + const PublicAccessType PublicAccessType::Path("Path"); + const PublicAccessType PublicAccessType::None("None"); + const AccountResourceType AccountResourceType::Account("account"); const PathResourceType PathResourceType::Directory("directory"); diff --git a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp index fb416994e..fd5ccf819 100644 --- a/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp +++ b/sdk/storage/azure-storage-files-datalake/test/datalake_file_system_client_test.cpp @@ -347,4 +347,53 @@ namespace Azure { namespace Storage { namespace Test { EXPECT_NO_THROW(clientSecretClient.Delete()); } } + + TEST_F(DataLakeFileSystemClientTest, GetSetAccessPolicy) + { + auto fileSystem = Files::DataLake::DataLakeFileSystemClient::CreateFromConnectionString( + AdlsGen2ConnectionString(), LowercaseRandomString()); + fileSystem.Create(); + + Files::DataLake::SetDataLakeFileSystemAccessPolicyOptions options; + options.AccessType = Files::DataLake::Models::PublicAccessType::Path; + Files::DataLake::Models::DataLakeSignedIdentifier identifier; + identifier.Id = RandomString(64); + identifier.StartsOn = std::chrono::system_clock::now() - std::chrono::minutes(1); + identifier.ExpiresOn = std::chrono::system_clock::now() + std::chrono::minutes(1); + identifier.Permissions = "r"; + options.SignedIdentifiers.emplace_back(identifier); + identifier.Id = RandomString(64); + identifier.StartsOn = std::chrono::system_clock::now() - std::chrono::minutes(2); + identifier.ExpiresOn = std::chrono::system_clock::now() + std::chrono::minutes(2); + identifier.Permissions = "racwdxlt"; + options.SignedIdentifiers.emplace_back(identifier); + + auto ret = fileSystem.SetAccessPolicy(options); + EXPECT_FALSE(ret->ETag.empty()); + EXPECT_TRUE(IsValidTime(ret->LastModified)); + + auto ret2 = fileSystem.GetAccessPolicy(); + EXPECT_EQ(ret2->ETag, ret->ETag); + EXPECT_EQ(ret2->LastModified, ret->LastModified); + EXPECT_EQ(ret2->AccessType, options.AccessType); + for (size_t i = 0; i < ret2->SignedIdentifiers.size(); ++i) + { + EXPECT_EQ(ret2->SignedIdentifiers[i].StartsOn, options.SignedIdentifiers[i].StartsOn); + EXPECT_EQ(ret2->SignedIdentifiers[i].ExpiresOn, options.SignedIdentifiers[i].ExpiresOn); + EXPECT_EQ(ret2->SignedIdentifiers[i].Id, options.SignedIdentifiers[i].Id); + EXPECT_EQ(ret2->SignedIdentifiers[i].Permissions, options.SignedIdentifiers[i].Permissions); + } + + options.AccessType = Files::DataLake::Models::PublicAccessType::FileSystem; + EXPECT_NO_THROW(fileSystem.SetAccessPolicy(options)); + ret2 = fileSystem.GetAccessPolicy(); + EXPECT_EQ(ret2->AccessType, options.AccessType); + + // options.AccessType = Files::DataLake::Models::PublicAccessType::Private; + // EXPECT_NO_THROW(fileSystem.SetAccessPolicy(options)); + // ret2 = fileSystem.GetAccessPolicy(); + // EXPECT_EQ(ret2->AccessType, options.AccessType.GetValue()); + + fileSystem.Delete(); + } }}} // namespace Azure::Storage::Test