diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/Errors.Clients.cs b/sdk/storage/Azure.Storage.Common/src/Shared/Errors.Clients.cs index 4e5464fa17e6..2a5fe3866810 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/Errors.Clients.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/Errors.Clients.cs @@ -78,7 +78,7 @@ public static InvalidOperationException SasBuilderEmptyParam(string builderName, => new InvalidOperationException($"SAS Uri cannot be generated. {builderName}.{paramName} cannot be set to create a {sasType} SAS."); public static InvalidOperationException SasIncorrectResourceType(string builderName, string builderParam, string value, string clientName) - => new InvalidOperationException($"SAS Uri cannot be generated. Expected {builderName}.{builderParam} to be set to {value} to generate" + + => new InvalidOperationException($"SAS Uri cannot be generated. Expected {builderName}.{builderParam} to be set to {value} to generate " + $"the respective SAS for the client, {clientName}"); public static ArgumentException InvalidPermission(char s) diff --git a/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md b/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md index 786a5ff1c0da..d04d43370d5e 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md +++ b/sdk/storage/Azure.Storage.Files.DataLake/CHANGELOG.md @@ -3,6 +3,7 @@ ## 12.20.0-beta.2 (Unreleased) ### Features Added +- Added GenerateUserDelegationSasUri() for DataLakePathClient, DataLakeFileSystemClient, and DataLakeDirectoryClient - Deprecated Read()/ReadAsync() in favor of ReadStreaming()/ReadStreamingAsync() and ReadContent()/ReadContentAsync() for DataLake #45418 ### Breaking Changes diff --git a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs index 884a12eb570c..a202d6300f50 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.net6.0.cs @@ -89,6 +89,12 @@ public DataLakeDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageSha public override System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public override System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public override Azure.Response GetAccessControl(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override System.Threading.Tasks.Task> GetAccessControlAsync(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Storage.Files.DataLake.DataLakeFileClient GetFileClient(string fileName) { throw null; } @@ -302,6 +308,12 @@ public DataLakeFileSystemClient(System.Uri fileSystemUri, Azure.Storage.StorageS public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeFileSystemSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeFileSystemSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Response GetAccessPolicy(Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAccessPolicyAsync(Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetDeletedPaths(string pathPrefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -388,6 +400,12 @@ public DataLakePathClient(System.Uri pathUri, Azure.Storage.StorageSharedKeyCred public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Response GetAccessControl(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAccessControlAsync(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Files.DataLake.DataLakeDirectoryClient GetParentDirectoryClientCore() { throw null; } diff --git a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs index 884a12eb570c..a202d6300f50 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/api/Azure.Storage.Files.DataLake.netstandard2.0.cs @@ -89,6 +89,12 @@ public DataLakeDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageSha public override System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public override System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public override System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public override Azure.Response GetAccessControl(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public override System.Threading.Tasks.Task> GetAccessControlAsync(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Storage.Files.DataLake.DataLakeFileClient GetFileClient(string fileName) { throw null; } @@ -302,6 +308,12 @@ public DataLakeFileSystemClient(System.Uri fileSystemUri, Azure.Storage.StorageS public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeFileSystemSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeFileSystemSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Response GetAccessPolicy(Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAccessPolicyAsync(Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetDeletedPaths(string pathPrefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -388,6 +400,12 @@ public DataLakePathClient(System.Uri pathUri, Azure.Storage.StorageSharedKeyCred public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasBuilder builder, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.DataLakeSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.DataLake.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Response GetAccessControl(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> GetAccessControlAsync(bool? userPrincipalName = default(bool?), Azure.Storage.Files.DataLake.Models.DataLakeRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Files.DataLake.DataLakeDirectoryClient GetParentDirectoryClientCore() { throw null; } diff --git a/sdk/storage/Azure.Storage.Files.DataLake/assets.json b/sdk/storage/Azure.Storage.Files.DataLake/assets.json index 556652aaba66..8bb5dc2c5e40 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/assets.json +++ b/sdk/storage/Azure.Storage.Files.DataLake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Files.DataLake", - "Tag": "net/storage/Azure.Storage.Files.DataLake_c09a71b442" + "Tag": "net/storage/Azure.Storage.Files.DataLake_aaedf543aa" } diff --git a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeDirectoryClient.cs b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeDirectoryClient.cs index 41b75adc88d1..7b2ba5c7cee3 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeDirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeDirectoryClient.cs @@ -3059,11 +3059,170 @@ public override Uri GenerateSasUri(DataLakeSasBuilder builder, out string string // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. builder = DataLakeSasBuilder.DeepCopy(builder); + SetBuilderAndValidate(builder); + DataLakeUriBuilder sasUri = new DataLakeUriBuilder(Uri) + { + Sas = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign) + }; + return sasUri.ToUri(); + } + #endregion + + #region GenerateUserDelegationSas + /// + /// The + /// returns a that generates a DataLake Directory Service Shared Access Signature (SAS) + /// Uri based on the Client properties and parameter passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Specifies the list of permissions to be associated with the SAS. + /// See . + /// + /// + /// Required. Specifies the time at which the SAS becomes invalid. This field + /// must be omitted if it has been specified in an associated stored access policy. + /// + /// + /// Required. A returned from + /// . + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public override Uri GenerateUserDelegationSasUri(DataLakeSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a DataLake Directory Service Shared Access Signature (SAS) + /// Uri based on the Client properties and parameter passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Specifies the list of permissions to be associated with the SAS. + /// See . + /// + /// + /// Required. Specifies the time at which the SAS becomes invalid. This field + /// must be omitted if it has been specified in an associated stored access policy. + /// + /// + /// Required. A returned from + /// . + /// + /// + /// For debugging purposes only. This string will be overwritten with the string to sign that was used to generate the SAS Uri. + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public override Uri GenerateUserDelegationSasUri(DataLakeSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => + GenerateUserDelegationSasUri(new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = FileSystemName, + Path = Path, + IsDirectory = true + }, userDelegationKey, out stringToSign); + + /// + /// The + /// returns a that generates a DataLake Directory Service Shared Access Signature (SAS) + /// Uri based on the Client properties and builder passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Used to generate a Shared Access Signature (SAS). + /// + /// + /// Required. A returned from + /// . + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public override Uri GenerateUserDelegationSasUri(DataLakeSasBuilder builder, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(builder, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a DataLake Directory Service Shared Access Signature (SAS) + /// Uri based on the Client properties and builder passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Used to generate a Shared Access Signature (SAS). + /// + /// + /// Required. A returned from + /// . + /// + /// + /// For debugging purposes only. This string will be overwritten with the string to sign that was used to generate the SAS Uri. + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public override Uri GenerateUserDelegationSasUri(DataLakeSasBuilder builder, UserDelegationKey userDelegationKey, out string stringToSign) + { + builder = builder ?? throw Errors.ArgumentNull(nameof(builder)); + userDelegationKey = userDelegationKey ?? throw Errors.ArgumentNull(nameof(userDelegationKey)); + + // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. + builder = DataLakeSasBuilder.DeepCopy(builder); + + SetBuilderAndValidate(builder); + if (string.IsNullOrEmpty(AccountName)) + { + throw Errors.SasClientMissingData(nameof(AccountName)); + } + + DataLakeUriBuilder sasUri = new DataLakeUriBuilder(Uri) + { + Sas = builder.ToSasQueryParameters(userDelegationKey, AccountName, out stringToSign) + }; + return sasUri.ToUri(); + } + #endregion + + private void SetBuilderAndValidate(DataLakeSasBuilder builder) + { // Assign builder's IsDirectory, FileSystemName, and Path, if they are null. builder.IsDirectory ??= GetType() == typeof(DataLakeDirectoryClient); builder.FileSystemName ??= FileSystemName; builder.Path ??= Path; + // Validate that builder is properly set if (!builder.IsDirectory.GetValueOrDefault(false)) { throw Errors.SasIncorrectResourceType( @@ -3086,12 +3245,6 @@ public override Uri GenerateSasUri(DataLakeSasBuilder builder, out string string nameof(DataLakeSasBuilder), nameof(Path)); } - DataLakeUriBuilder sasUri = new DataLakeUriBuilder(Uri) - { - Sas = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign) - }; - return sasUri.ToUri(); } - #endregion } } diff --git a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeFileSystemClient.cs b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeFileSystemClient.cs index 96cccd792d8c..5a5e9ca8650c 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeFileSystemClient.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakeFileSystemClient.cs @@ -3287,26 +3287,158 @@ public virtual Uri GenerateSasUri( // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. builder = DataLakeSasBuilder.DeepCopy(builder); - // Assign builder's FileSystemName, if it is null. - builder.FileSystemName ??= Name; - - if (!builder.FileSystemName.Equals(Name, StringComparison.InvariantCulture)) + SetBuilderAndValidate(builder); + DataLakeUriBuilder sasUri = new DataLakeUriBuilder(Uri) { - throw Errors.SasNamesNotMatching( - nameof(builder.FileSystemName), - nameof(DataLakeSasBuilder), - nameof(Name)); - } - if (!string.IsNullOrEmpty(builder.Path)) + Sas = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign) + }; + return sasUri.ToUri(); + } + #endregion + + #region GenerateUserDelegationSas + /// + /// The + /// returns a that generates a DataLake FileSystem Service + /// Shared Access Signature (SAS) Uri based on the Client properties and parameters passed. + /// The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Specifies the list of permissions to be associated with the SAS. + /// See . + /// + /// + /// Required. Specifies the time at which the SAS becomes invalid. This field + /// must be omitted if it has been specified in an associated stored access policy. + /// + /// + /// Required. A returned from + /// . + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeFileSystemSasPermissions permissions, DateTimeOffset expiresOn, Models.UserDelegationKey userDelegationKey) => + GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a DataLake FileSystem Service + /// Shared Access Signature (SAS) Uri based on the Client properties and parameters passed. + /// The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Specifies the list of permissions to be associated with the SAS. + /// See . + /// + /// + /// Required. Specifies the time at which the SAS becomes invalid. This field + /// must be omitted if it has been specified in an associated stored access policy. + /// + /// + /// Required. A returned from + /// . + /// + /// + /// For debugging purposes only. This string will be overwritten with the string to sign that was used to generate the SAS Uri. + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeFileSystemSasPermissions permissions, DateTimeOffset expiresOn, Models.UserDelegationKey userDelegationKey, out string stringToSign) => + GenerateUserDelegationSasUri(new DataLakeSasBuilder(permissions, expiresOn) { FileSystemName = Name }, userDelegationKey, out stringToSign); + + /// + /// The returns a + /// that generates a DataLake FileSystem Service Shared Access Signature (SAS) + /// Uri based on the Client properties and builder passed. + /// The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Used to generate a Shared Access Signature (SAS). + /// + /// + /// Required. A returned from + /// . + /// + /// + /// A on successfully deleting. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeSasBuilder builder, Models.UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(builder, userDelegationKey, out _); + + /// + /// The returns a + /// that generates a DataLake FileSystem Service Shared Access Signature (SAS) + /// Uri based on the Client properties and builder passed. + /// The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Used to generate a Shared Access Signature (SAS). + /// + /// + /// Required. A returned from + /// . + /// + /// + /// For debugging purposes only. This string will be overwritten with the string to sign that was used to generate the SAS Uri. + /// + /// + /// A on successfully deleting. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeSasBuilder builder, Models.UserDelegationKey userDelegationKey, out string stringToSign) + { + builder = builder ?? throw Errors.ArgumentNull(nameof(builder)); + userDelegationKey = userDelegationKey ?? throw Errors.ArgumentNull(nameof(userDelegationKey)); + + // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. + builder = DataLakeSasBuilder.DeepCopy(builder); + + SetBuilderAndValidate(builder); + if (string.IsNullOrEmpty(AccountName)) { - throw Errors.SasBuilderEmptyParam( - nameof(builder), - nameof(builder.Path), - nameof(Constants.DataLake.FileSystemName)); + throw Errors.SasClientMissingData(nameof(AccountName)); } + DataLakeUriBuilder sasUri = new DataLakeUriBuilder(Uri) { - Sas = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign) + Sas = builder.ToSasQueryParameters(userDelegationKey, AccountName, out stringToSign) }; return sasUri.ToUri(); } @@ -3622,6 +3754,28 @@ protected internal virtual DataLakeServiceClient GetParentServiceClientCore() return _parentServiceClient; } #endregion + + private void SetBuilderAndValidate(DataLakeSasBuilder builder) + { + // Assign builder's FileSystemName, if it is null. + builder.FileSystemName ??= Name; + + // Validate that builder is properly set + if (!builder.FileSystemName.Equals(Name, StringComparison.InvariantCulture)) + { + throw Errors.SasNamesNotMatching( + nameof(builder.FileSystemName), + nameof(DataLakeSasBuilder), + nameof(Name)); + } + if (!string.IsNullOrEmpty(builder.Path)) + { + throw Errors.SasBuilderEmptyParam( + nameof(builder), + nameof(builder.Path), + nameof(Constants.DataLake.FileSystemName)); + } + } } namespace Specialized diff --git a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakePathClient.cs b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakePathClient.cs index c876715c2f7b..cd7d7e0ec75d 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakePathClient.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/src/DataLakePathClient.cs @@ -529,7 +529,7 @@ internal DataLakePathClient( (PathRestClient dfsPathRestClient, PathRestClient blobPathRestClient) = BuildPathRestClients(_dfsUri, _blobUri); _pathRestClient = dfsPathRestClient; - _blobPathRestClient = blobPathRestClient; + _blobPathRestClient = blobPathRestClient; DataLakeErrors.VerifyHttpsCustomerProvidedKey(_uri, _clientConfiguration.CustomerProvidedKey); } @@ -1166,7 +1166,7 @@ internal virtual async Task> CreateInternal( if (expiresOn.HasValue && timeToExpire.HasValue) { - throw new ArgumentException($"{nameof(DataLakePathCreateOptions)}.{nameof(DataLakePathCreateOptions.ScheduleDeletionOptions.ExpiresOn)} and {nameof(DataLakePathCreateOptions)}.{nameof(DataLakePathCreateOptions.ScheduleDeletionOptions.TimeToExpire)} cannot both be set."); + throw new ArgumentException($"{nameof(DataLakePathCreateOptions)}.{nameof(DataLakePathCreateOptions.ScheduleDeletionOptions.ExpiresOn)} and {nameof(DataLakePathCreateOptions)}.{nameof(DataLakePathCreateOptions.ScheduleDeletionOptions.TimeToExpire)} cannot both be set."); } try @@ -1418,10 +1418,10 @@ public virtual async Task> CreateIfNotExistsAsync( public virtual Response CreateIfNotExists( #pragma warning restore AZC0002 // DO ensure all service methods, both asynchronous and synchronous, take an optional CancellationToken parameter called cancellationToken. PathResourceType resourceType, - PathHttpHeaders httpHeaders , + PathHttpHeaders httpHeaders, Metadata metadata, string permissions, - string umask , + string umask, CancellationToken cancellationToken) => CreateIfNotExistsInternal( resourceType: resourceType, @@ -3946,36 +3946,158 @@ public virtual Uri GenerateSasUri(DataLakeSasBuilder builder, out string stringT // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. builder = DataLakeSasBuilder.DeepCopy(builder); - // Assign builder's IsDirectory, FileSystemName, and Path, if they are null. - builder.IsDirectory ??= GetType() == typeof(DataLakeDirectoryClient); - builder.FileSystemName ??= FileSystemName; - builder.Path ??= Path; - - if (builder.IsDirectory.GetValueOrDefault(false)) + SetBuilderAndValidate(builder); + DataLakeUriBuilder sasUri = new DataLakeUriBuilder(Uri) { - throw Errors.SasIncorrectResourceType( - nameof(builder), - nameof(builder.IsDirectory), - nameof(Constants.FalseName), - nameof(this.GetType)); - } - if (!builder.FileSystemName.Equals(FileSystemName, StringComparison.InvariantCulture)) + Sas = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign) + }; + return sasUri.ToUri(); + } + #endregion + + #region GenerateUserDelegationSas + /// + /// The + /// returns a that generates a DataLake Path Service Shared Access Signature (SAS) + /// Uri based on the Client properties and parameter passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Specifies the list of permissions to be associated with the SAS. + /// See . + /// + /// + /// Required. Specifies the time at which the SAS becomes invalid. This field + /// must be omitted if it has been specified in an associated stored access policy. + /// + /// + /// Required. A returned from + /// . + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a DataLake Path Service Shared Access Signature (SAS) + /// Uri based on the Client properties and parameter passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Specifies the list of permissions to be associated with the SAS. + /// See . + /// + /// + /// Required. Specifies the time at which the SAS becomes invalid. This field + /// must be omitted if it has been specified in an associated stored access policy. + /// + /// + /// Required. A returned from + /// . + /// + /// + /// For debugging purposes only. This string will be overwritten with the string to sign that was used to generate the SAS Uri. + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if a failure occurs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => + GenerateUserDelegationSasUri(new DataLakeSasBuilder(permissions, expiresOn) { - throw Errors.SasNamesNotMatching( - nameof(builder.FileSystemName), - nameof(DataLakeSasBuilder), - nameof(FileSystemName)); - } - if (!builder.Path.Equals(Path, StringComparison.InvariantCulture)) + FileSystemName = FileSystemName, + Path = Path + }, userDelegationKey, out stringToSign); + + /// + /// The + /// returns a that generates a DataLake Path Service Shared Access Signature (SAS) + /// Uri based on the Client properties and builder passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Used to generate a Shared Access Signature (SAS). + /// + /// + /// Required. A returned from + /// . + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeSasBuilder builder, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(builder, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a DataLake Path Service Shared Access Signature (SAS) + /// Uri based on the Client properties and builder passed. The SAS is signed by the user delegation key passed in. + /// + /// For more information, see + /// + /// Creating an user delegation SAS. + /// + /// + /// Required. Used to generate a Shared Access Signature (SAS). + /// + /// + /// Required. A returned from + /// . + /// + /// + /// For debugging purposes only. This string will be overwritten with the string to sign that was used to generate the SAS Uri. + /// + /// + /// A containing the SAS Uri. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public virtual Uri GenerateUserDelegationSasUri(DataLakeSasBuilder builder, UserDelegationKey userDelegationKey, out string stringToSign) + { + builder = builder ?? throw Errors.ArgumentNull(nameof(builder)); + userDelegationKey = userDelegationKey ?? throw Errors.ArgumentNull(nameof(userDelegationKey)); + + // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. + builder = DataLakeSasBuilder.DeepCopy(builder); + + SetBuilderAndValidate(builder); + if (string.IsNullOrEmpty(AccountName)) { - throw Errors.SasNamesNotMatching( - nameof(builder.Path), - nameof(DataLakeSasBuilder), - nameof(Path)); + throw Errors.SasClientMissingData(nameof(AccountName)); } + DataLakeUriBuilder sasUri = new DataLakeUriBuilder(Uri) { - Sas = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign) + Sas = builder.ToSasQueryParameters(userDelegationKey, AccountName, out stringToSign) }; return sasUri.ToUri(); } @@ -4042,6 +4164,38 @@ protected internal virtual DataLakeDirectoryClient GetParentDirectoryClientCore( return _parentDirectoryClient; } #endregion + + private void SetBuilderAndValidate(DataLakeSasBuilder builder) + { + // Assign builder's IsDirectory, FileSystemName, and Path, if they are null. + builder.IsDirectory ??= GetType() == typeof(DataLakeDirectoryClient); + builder.FileSystemName ??= FileSystemName; + builder.Path ??= Path; + + // Validate that builder is properly set + if (builder.IsDirectory.GetValueOrDefault(false)) + { + throw Errors.SasIncorrectResourceType( + nameof(builder), + nameof(builder.IsDirectory), + Constants.FalseName, + nameof(this.GetType)); + } + if (!builder.FileSystemName.Equals(FileSystemName, StringComparison.InvariantCulture)) + { + throw Errors.SasNamesNotMatching( + nameof(builder.FileSystemName), + nameof(DataLakeSasBuilder), + nameof(FileSystemName)); + } + if (!builder.Path.Equals(Path, StringComparison.InvariantCulture)) + { + throw Errors.SasNamesNotMatching( + nameof(builder.Path), + nameof(DataLakeSasBuilder), + nameof(Path)); + } + } } namespace Specialized diff --git a/sdk/storage/Azure.Storage.Files.DataLake/tests/DirectoryClientTests.cs b/sdk/storage/Azure.Storage.Files.DataLake/tests/DirectoryClientTests.cs index 44f5b378e26d..83938361fb0d 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/tests/DirectoryClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/tests/DirectoryClientTests.cs @@ -6470,7 +6470,424 @@ public void GenerateSas_BuilderIsDirectoryError() // Act TestHelper.AssertExpectedException( () => directoryClient.GenerateSasUri(sasBuilder), - new InvalidOperationException("SAS Uri cannot be generated. Expected builder.IsDirectory to be set to true to generatethe respective SAS for the client, GetType")); + new InvalidOperationException("SAS Uri cannot be generated. Expected builder.IsDirectory to be set to true to generate the respective SAS for the client, GetType")); + } + #endregion + + #region GenerateUserDelegationSasTests + [RecordedTest] + public async Task GenerateUserDelegationSas_RequiredParameters() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = directoryClient.GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out stringToSign); + + // Assert + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = true + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path, + Sas = sasBuilder.ToSasQueryParameters(userDelegationKey, directoryClient.AccountName) + }; + + Assert.AreEqual(expectedUri.ToUri(), sasUri); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_Builder() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = true, + }; + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = directoryClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey, out stringToSign); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = true, + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, directoryClient.AccountName); + Assert.AreEqual(expectedUri.ToUri(), sasUri); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNull() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => directoryClient.GenerateUserDelegationSasUri(null, userDelegationKey, out stringToSign), + new ArgumentNullException("builder")); + } + + [RecordedTest] + public void GenerateUserDelegationSas_UserDelegationKeyNull() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = true, + }; + + string stringToSign = null; + + // Assert + TestHelper.AssertExpectedException( + () => directoryClient.GenerateUserDelegationSasUri(sasBuilder, null, out stringToSign), + new ArgumentNullException("userDelegationKey")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullFileSystemName() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = null, + Path = path, + IsDirectory = true, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = directoryClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = true, + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, directoryClient.AccountName); + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderWrongFileSystemName() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string directoryName = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = directoryName + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = GetNewFileSystemName(), // different filesytem name + Path = directoryName, + IsDirectory = true + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => directoryClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. DataLakeSasBuilder.FileSystemName does not match FileSystemName in the Client. DataLakeSasBuilder.FileSystemName must either be left empty or match the FileSystemName in the Client")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullPath() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = null, + IsDirectory = true, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = directoryClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = true, + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, directoryClient.AccountName); + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderWrongPathName() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string directoryName = GetNewDirectoryName(); + string fileSystemName = GetNewFileSystemName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = directoryName + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = GetNewDirectoryName(), // different directory name + IsDirectory = true, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => directoryClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. DataLakeSasBuilder.Path does not match Path in the Client. DataLakeSasBuilder.Path must either be left empty or match the Path in the Client")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderIsDirectoryNull() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = null, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = directoryClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = true, + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, directoryClient.AccountName); + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderIsDirectoryError() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string directoryName = GetNewDirectoryName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = directoryName + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeDirectoryClient directoryClient = InstrumentClient(new DataLakeDirectoryClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = directoryName, + IsDirectory = false, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => directoryClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. Expected builder.IsDirectory to be set to true to generate the respective SAS for the client, GetType")); } #endregion diff --git a/sdk/storage/Azure.Storage.Files.DataLake/tests/FileClientTests.cs b/sdk/storage/Azure.Storage.Files.DataLake/tests/FileClientTests.cs index d43891039bda..ef9f73e40e18 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/tests/FileClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/tests/FileClientTests.cs @@ -6356,7 +6356,409 @@ public void GenerateSas_BuilderIsDirectoryError() // Act TestHelper.AssertExpectedException( () => fileClient.GenerateSasUri(sasBuilder), - new InvalidOperationException("SAS Uri cannot be generated. Expected builder.IsDirectory to be set to FalseName to generatethe respective SAS for the client, GetType")); + new InvalidOperationException("SAS Uri cannot be generated. Expected builder.IsDirectory to be set to false to generate the respective SAS for the client, GetType")); + } + #endregion + + #region GenerateUserDelegationSasTests + [RecordedTest] + public async Task GenerateUserDelegationSas_RequiredParameters() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileClient.GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileClient.AccountName) + }; + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_Builder() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileClient.AccountName) + }; + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNull() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => fileClient.GenerateUserDelegationSasUri(null, userDelegationKey), + new ArgumentNullException("builder")); + } + + [RecordedTest] + public void GenerateUserDelegationSas_UserDelegationKeyNull() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path + }; + + // Act + TestHelper.AssertExpectedException( + () => fileClient.GenerateUserDelegationSasUri(sasBuilder, null), + new ArgumentNullException("userDelegationKey")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullFileSystemName() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = null, + Path = path + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileClient.AccountName) + }; + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderWrongFileSystemName() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = GetNewFileSystemName(), // different filesystem name + Path = path, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => fileClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. DataLakeSasBuilder.FileSystemName does not match FileSystemName in the Client. DataLakeSasBuilder.FileSystemName must either be left empty or match the FileSystemName in the Client")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullFileName() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = null + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileClient.AccountName) + }; + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderWrongFileName() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = GetNewFileName(), // different path + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => fileClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. DataLakeSasBuilder.Path does not match Path in the Client. DataLakeSasBuilder.Path must either be left empty or match the Path in the Client")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullIsDirectory() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path + }; + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = null + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + IsDirectory = false + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = path, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileClient.AccountName) + }; + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderIsDirectoryError() + { + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string fileName = GetNewFileName(); + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + DirectoryOrFilePath = fileName + }; + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + + DataLakeFileClient fileClient = InstrumentClient(new DataLakeFileClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = GetNewFileName(), + IsDirectory = true, + IPRange = new SasIPRange(System.Net.IPAddress.None, System.Net.IPAddress.None), + ExpiresOn = Recording.UtcNow.AddHours(+1) + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => fileClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. Expected builder.IsDirectory to be set to false to generate the respective SAS for the client, GetType")); } #endregion diff --git a/sdk/storage/Azure.Storage.Files.DataLake/tests/FileSystemClientTests.cs b/sdk/storage/Azure.Storage.Files.DataLake/tests/FileSystemClientTests.cs index 2c0af9ceaf4e..6f719cb694eb 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/tests/FileSystemClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/tests/FileSystemClientTests.cs @@ -3329,6 +3329,272 @@ public void GenerateSas_BuilderWrongName() } #endregion + #region GenerateUserDelegationSasTests + [RecordedTest] + public async Task GenerateUserDelegationSas_RequiredParameters() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + DataLakeFileSystemSasPermissions permissions = DataLakeFileSystemSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName + }; + + DataLakeFileSystemClient fileSystemClient = InstrumentClient(new DataLakeFileSystemClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileSystemClient.GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out stringToSign); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileSystemClient.AccountName) + }; + Assert.AreEqual(expectedUri.ToUri(), sasUri); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_Builder() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + DataLakeFileSystemSasPermissions permissions = DataLakeFileSystemSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName + }; + + DataLakeFileSystemClient fileSystemClient = InstrumentClient(new DataLakeFileSystemClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemClient.Name + }; + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileSystemClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey, out stringToSign); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileSystemClient.AccountName) + }; + + Assert.AreEqual(expectedUri.ToUri(), sasUri); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNull() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName + }; + + DataLakeFileSystemClient fileSystemClient = InstrumentClient(new DataLakeFileSystemClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => fileSystemClient.GenerateUserDelegationSasUri(null, userDelegationKey, out stringToSign), + new ArgumentNullException("builder")); + } + + [RecordedTest] + public void GenerateUserDelegationSas_UserDelegationKeyNull() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + DataLakeFileSystemSasPermissions permissions = DataLakeFileSystemSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName + }; + + DataLakeFileSystemClient fileSystemClient = InstrumentClient(new DataLakeFileSystemClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemClient.Name + }; + + string stringToSign = null; + + // Act + TestHelper.AssertExpectedException( + () => fileSystemClient.GenerateUserDelegationSasUri(sasBuilder, null, out stringToSign), + new ArgumentNullException("userDelegationKey")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullName() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + DataLakeFileSystemSasPermissions permissions = DataLakeFileSystemSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName + }; + + DataLakeFileSystemClient fileSystemClient = InstrumentClient(new DataLakeFileSystemClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = null + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = fileSystemClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName, + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, fileSystemClient.AccountName) + }; + + Assert.AreEqual(expectedUri.ToUri(), sasUri); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderWrongName() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName + }; + + DataLakeFileSystemSasPermissions permissions = DataLakeFileSystemSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeFileSystemClient fileSystemClient = InstrumentClient(new DataLakeFileSystemClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = GetNewFileSystemName(), // different filesytem name + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => fileSystemClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. DataLakeSasBuilder.FileSystemName does not match Name in the Client. DataLakeSasBuilder.FileSystemName must either be left empty or match the Name in the Client")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderIncorrectlySetPath() + { + // Arrange + TestConstants constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + + Uri serviceUri = new Uri($"https://{constants.Sas.Account}.dfs.core.windows.net"); + DataLakeUriBuilder dataLakeUriBuilder = new DataLakeUriBuilder(serviceUri) + { + FileSystemName = fileSystemName + }; + + DataLakeFileSystemSasPermissions permissions = DataLakeFileSystemSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DataLakeFileSystemClient fileSystemClient = InstrumentClient(new DataLakeFileSystemClient( + dataLakeUriBuilder.ToUri(), + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = GetNewFileName() + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => fileSystemClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. builder.Path cannot be set to create a FileSystemName SAS.")); + } + #endregion + [RecordedTest] public void CanMockClientConstructors() { diff --git a/sdk/storage/Azure.Storage.Files.DataLake/tests/PathClientTests.cs b/sdk/storage/Azure.Storage.Files.DataLake/tests/PathClientTests.cs index 64d119eb3c86..f95ecaeac8d5 100644 --- a/sdk/storage/Azure.Storage.Files.DataLake/tests/PathClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.DataLake/tests/PathClientTests.cs @@ -409,6 +409,368 @@ public void GenerateSas_BuilderIsDirectoryError() } #endregion + #region GenerateUserDelegationSasTests + [RecordedTest] + public async Task GenerateUserDelegationSas_RequiredParameters() + { + // Arrange + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + var blobEndpoint = new Uri("http://127.0.0.1/" + constants.Sas.Account + "/" + fileSystemName + "/" + path); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobEndpoint, + GetOptions())); + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = pathClient.GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out stringToSign); + + // Assert + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path + }; + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(blobEndpoint) + { + Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, pathClient.AccountName) + }; + Assert.AreEqual(expectedUri.ToUri().ToString(), sasUri.ToString()); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_Builder() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DateTimeOffset startsOn = Recording.UtcNow.AddHours(-1); + var blobEndpoint = new Uri("http://127.0.0.1/" + constants.Sas.Account + "/" + fileSystemName + "/" + path); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobEndpoint, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + StartsOn = startsOn + }; + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = pathClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey, out stringToSign); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(blobEndpoint); + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + StartsOn = startsOn + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, pathClient.AccountName); + Assert.AreEqual(expectedUri.ToUri().ToString(), sasUri.ToString()); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNull() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + var blobEndpoint = new Uri("http://127.0.0.1/" + constants.Sas.Account + "/" + fileSystemName + "/" + path); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobEndpoint, + GetOptions())); + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => pathClient.GenerateUserDelegationSasUri(null, userDelegationKey, out stringToSign), + new ArgumentNullException("builder")); + } + + [RecordedTest] + public void GenerateUserDelegationSas_UserDelegationKeyNull() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DateTimeOffset startsOn = Recording.UtcNow.AddHours(-1); + var blobEndpoint = new Uri("http://127.0.0.1/" + constants.Sas.Account + "/" + fileSystemName + "/" + path); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobEndpoint, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + StartsOn = startsOn + }; + + string stringToSign = null; + + // Act + TestHelper.AssertExpectedException( + () => pathClient.GenerateUserDelegationSasUri(sasBuilder, null, out stringToSign), + new ArgumentNullException("userDelegationKey")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullFileSystemName() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DateTimeOffset startsOn = Recording.UtcNow.AddHours(-1); + var blobEndpoint = new Uri("http://127.0.0.1/" + constants.Sas.Account + "/" + fileSystemName + "/" + path); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobEndpoint, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = null, + Path = path, + StartsOn = startsOn + }; + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = pathClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey, out stringToSign); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(blobEndpoint); + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + StartsOn = startsOn + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, pathClient.AccountName); + Assert.AreEqual(expectedUri.ToUri().ToString(), sasUri.ToString()); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderWrongFileSystemName() + { + // Arrange + var constants = TestConstants.Create(this); + var blobEndpoint = new Uri("http://127.0.0.1/"); + UriBuilder blobUriBuilder = new UriBuilder(blobEndpoint); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + blobUriBuilder.Path += constants.Sas.Account + "/" + GetNewFileSystemName() + "/" + path; + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobUriBuilder.Uri, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = GetNewFileSystemName(), // different filesystem name + Path = path, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => pathClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. DataLakeSasBuilder.FileSystemName does not match FileSystemName in the Client. DataLakeSasBuilder.FileSystemName must either be left empty or match the FileSystemName in the Client")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullPath() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DateTimeOffset startsOn = Recording.UtcNow.AddHours(-1); + var blobEndpoint = new Uri("http://127.0.0.1/" + constants.Sas.Account + "/" + fileSystemName + "/" + path); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobEndpoint, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = null, + StartsOn = startsOn + }; + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = pathClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey, out stringToSign); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(blobEndpoint); + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + StartsOn = startsOn + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, pathClient.AccountName); + Assert.AreEqual(expectedUri.ToUri().ToString(), sasUri.ToString()); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderWrongPath() + { + // Arrange + var constants = TestConstants.Create(this); + var blobEndpoint = new Uri("http://127.0.0.1/"); + UriBuilder blobUriBuilder = new UriBuilder(blobEndpoint); + string fileSystemName = GetNewFileSystemName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + blobUriBuilder.Path += constants.Sas.Account + "/" + fileSystemName + "/" + GetNewFileName(); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobUriBuilder.Uri, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = GetNewFileName(), // different path + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => pathClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. DataLakeSasBuilder.Path does not match Path in the Client. DataLakeSasBuilder.Path must either be left empty or match the Path in the Client")); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderNullIsDirectory() + { + var constants = TestConstants.Create(this); + string fileSystemName = GetNewFileSystemName(); + string path = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + DateTimeOffset startsOn = Recording.UtcNow.AddHours(-1); + var blobEndpoint = new Uri("http://127.0.0.1/" + constants.Sas.Account + "/" + fileSystemName + "/" + path); + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobEndpoint, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + StartsOn = startsOn, + IsDirectory = null + }; + + string stringToSign = null; + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + Uri sasUri = pathClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey, out stringToSign); + + // Assert + DataLakeUriBuilder expectedUri = new DataLakeUriBuilder(blobEndpoint); + DataLakeSasBuilder sasBuilder2 = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = path, + StartsOn = startsOn, + IsDirectory = false + }; + expectedUri.Sas = sasBuilder2.ToSasQueryParameters(userDelegationKey, pathClient.AccountName); + Assert.AreEqual(expectedUri.ToUri().ToString(), sasUri.ToString()); + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + public async Task GenerateUserDelegationSas_BuilderIsDirectoryError() + { + var constants = TestConstants.Create(this); + var blobEndpoint = new Uri("http://127.0.0.1/"); + UriBuilder blobUriBuilder = new UriBuilder(blobEndpoint); + string fileSystemName = GetNewFileSystemName(); + string fileName = GetNewFileName(); + DataLakeSasPermissions permissions = DataLakeSasPermissions.Read; + DateTimeOffset expiresOn = Recording.UtcNow.AddHours(+1); + blobUriBuilder.Path += constants.Sas.Account + "/" + fileSystemName + "/" + fileName; + DataLakePathClient pathClient = InstrumentClient(new DataLakePathClient( + blobUriBuilder.Uri, + GetOptions())); + + DataLakeSasBuilder sasBuilder = new DataLakeSasBuilder(permissions, expiresOn) + { + FileSystemName = fileSystemName, + Path = fileName, + IsDirectory = true, + }; + + Response userDelegationKeyResponse = await GetServiceClient_OAuth().GetUserDelegationKeyAsync( + startsOn: null, + expiresOn: Recording.UtcNow.AddHours(1)); + UserDelegationKey userDelegationKey = userDelegationKeyResponse.Value; + + // Act + TestHelper.AssertExpectedException( + () => pathClient.GenerateUserDelegationSasUri(sasBuilder, userDelegationKey), + new InvalidOperationException("SAS Uri cannot be generated. Expected builder.IsDirectory to be set to false to generate the respective SAS for the client, GetType")); + } + #endregion + [RecordedTest] public void CanMockClientConstructors() {