From b6350900073526ce2bac26bdcc487aa3df9c58f7 Mon Sep 17 00:00:00 2001 From: Jocelyn Schreppler Date: Thu, 5 Oct 2023 12:41:10 -0400 Subject: [PATCH 1/7] datamovemnet access to header and audience --- .../src/ShareClient.cs | 5 ++- .../src/ShareClientConfiguration.cs | 2 ++ .../src/ShareDirectoryClient.cs | 5 ++- .../src/ShareFileClient.cs | 35 ++++++++++++++++++- .../src/ShareServiceClient.cs | 5 ++- 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs index 8d3406e9bf24..1427310d6313 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs @@ -346,7 +346,10 @@ internal ShareClient( sasCredential: sasCredential, tokenCredential: tokenCredential, clientDiagnostics: new ClientDiagnostics(options), - clientOptions: options); + clientOptions: options) + { + Audience = options.Audience ?? ShareAudience.PublicAudience, + }; _shareRestClient = BuildShareRestClient(shareUri); } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientConfiguration.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientConfiguration.cs index 1d799e151516..900c8ad47e64 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientConfiguration.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClientConfiguration.cs @@ -14,6 +14,8 @@ internal class ShareClientConfiguration : StorageClientConfiguration public TransferValidationOptions TransferValidation { get; internal set; } + public ShareAudience Audience { get; internal set; } + /// /// Create a with shared key authentication. /// diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs index 4b94f5fddc28..a67c7249f5a1 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs @@ -412,7 +412,10 @@ internal ShareDirectoryClient( sasCredential: sasCredential, tokenCredential: tokenCredential, clientDiagnostics: new ClientDiagnostics(options), - clientOptions: options); + clientOptions: options) + { + Audience = options.Audience ?? ShareAudience.PublicAudience, + }; _directoryRestClient = BuildDirectoryRestClient(directoryUri); } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs index c9605b686651..d1031e41b6aa 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs @@ -422,7 +422,10 @@ internal ShareFileClient( sasCredential: sasCredential, tokenCredential: tokenCredential, clientDiagnostics: new ClientDiagnostics(options), - clientOptions: options); + clientOptions: options) + { + Audience = options.Audience ?? ShareAudience.PublicAudience, + }; _fileRestClient = BuildFileRestClient(fileUri); } @@ -498,6 +501,36 @@ private void SetNameFieldsIfNull() } } + #region internal static accessors for Azure.Storage.DataMovement.Blobs + /// + /// Get a 's + /// for passing the authorization when performing service to service copy + /// where OAuth is necessary to authenticate the source. + /// + /// + /// The storage client which to generate the + /// authorization header off of. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// The BlobServiceClient's HttpPipeline. + protected static async Task<(HttpAuthorization Authorization, ShareAudience Audience)> GetCopyAuthorizationHeaderAsync( + ShareFileClient client, + CancellationToken cancellationToken = default) + { + if (client.ClientConfiguration.TokenCredential != default) + { + return ( + await client.ClientConfiguration.TokenCredential.GetCopyAuthorizationHeaderAsync(cancellationToken).ConfigureAwait(false), + client.ClientConfiguration.Audience + ); + } + return default; + } + #endregion internal static accessors for Azure.Storage.DataMovement.Blobs + #region Create /// /// Creates a new file or replaces an existing file. diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs index 296459388823..96984c5807fd 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs @@ -325,7 +325,10 @@ internal ShareServiceClient( sasCredential: sasCredential, tokenCredential: tokenCredential, clientDiagnostics: new ClientDiagnostics(options), - clientOptions: options); + clientOptions: options) + { + Audience = options.Audience ?? ShareAudience.PublicAudience, + }; _serviceRestClient = BuildServiceRestClient(); } From 19b3d4797ae3c5f60c33dc5e2c1bff557c6e74e0 Mon Sep 17 00:00:00 2001 From: Jocelyn Schreppler Date: Fri, 6 Oct 2023 16:27:42 -0400 Subject: [PATCH 2/7] include audience in HttpAuthorization --- .../src/ShareFileClientInternals.cs | 18 ++++++++++++++++++ .../src/ShareFileStorageResource.cs | 7 +++---- .../src/ShareFileClient.cs | 12 +++++++----- 3 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileClientInternals.cs diff --git a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileClientInternals.cs b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileClientInternals.cs new file mode 100644 index 000000000000..648ed97d52df --- /dev/null +++ b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileClientInternals.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Threading; +using System.Threading.Tasks; +using Azure.Storage.Files.Shares; +using Azure.Storage.Files.Shares.Models; + +namespace Azure.Storage.DataMovement.Blobs +{ + internal class ShareFileClientInternals : ShareFileClient + { + public static Task GetCopyAuthorizationTokenAsync( + ShareFileClient client, + CancellationToken cancellationToken) + => ShareFileClient.GetCopyAuthorizationHeaderAsync(client, cancellationToken); + } +} diff --git a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileStorageResource.cs b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileStorageResource.cs index e141e14a50df..efff697fc3c8 100644 --- a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileStorageResource.cs +++ b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareFileStorageResource.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Azure.Core; +using Azure.Storage.DataMovement.Blobs; using Azure.Storage.Files.Shares; using Azure.Storage.Files.Shares.Models; @@ -171,11 +172,9 @@ protected override async Task DeleteIfExistsAsync(CancellationToken cancel return await ShareFileClient.DeleteIfExistsAsync(cancellationToken: cancellationToken).ConfigureAwait(false); } - protected override Task GetCopyAuthorizationHeaderAsync(CancellationToken cancellationToken = default) + protected override async Task GetCopyAuthorizationHeaderAsync(CancellationToken cancellationToken = default) { - CancellationHelper.ThrowIfCancellationRequested(cancellationToken); - // TODO: This needs an update to ShareFileClient to allow getting the Copy Authorization Token - throw new NotImplementedException(); + return await ShareFileClientInternals.GetCopyAuthorizationTokenAsync(ShareFileClient, cancellationToken).ConfigureAwait(false); } protected override async Task GetPropertiesAsync(CancellationToken cancellationToken = default) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs index d1031e41b6aa..a00b0f72e56a 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs @@ -516,16 +516,18 @@ private void SetNameFieldsIfNull() /// notifications that the operation should be cancelled. /// /// The BlobServiceClient's HttpPipeline. - protected static async Task<(HttpAuthorization Authorization, ShareAudience Audience)> GetCopyAuthorizationHeaderAsync( + protected static async Task GetCopyAuthorizationHeaderAsync( ShareFileClient client, CancellationToken cancellationToken = default) { if (client.ClientConfiguration.TokenCredential != default) { - return ( - await client.ClientConfiguration.TokenCredential.GetCopyAuthorizationHeaderAsync(cancellationToken).ConfigureAwait(false), - client.ClientConfiguration.Audience - ); + AccessToken accessToken = await client.ClientConfiguration.TokenCredential.GetTokenAsync( + new TokenRequestContext(new string[] { client.ClientConfiguration.Audience.ToString() }), + cancellationToken).ConfigureAwait(false); + return new HttpAuthorization( + Constants.CopyHttpAuthorization.BearerScheme, + accessToken.Token); } return default; } From b5263c8f688ebe27c5737c49dfe860dd1383c405 Mon Sep 17 00:00:00 2001 From: Jocelyn Schreppler Date: Mon, 9 Oct 2023 11:51:21 -0400 Subject: [PATCH 3/7] tests --- .../tests/ShareFileResourceTests.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/tests/ShareFileResourceTests.cs b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/tests/ShareFileResourceTests.cs index 5555330d32fe..163948699234 100644 --- a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/tests/ShareFileResourceTests.cs +++ b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/tests/ShareFileResourceTests.cs @@ -8,11 +8,13 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using Azure.Core; using Azure.Core.TestFramework; using Azure.Storage.Files.Shares; using Azure.Storage.Files.Shares.Models; using Azure.Storage.Test; using Moq; +using Moq.Protected; using NUnit.Framework; namespace Azure.Storage.DataMovement.Files.Shares.Tests @@ -544,5 +546,37 @@ await TestHelper.AssertExpectedExceptionAsync( Times.Once()); mock.VerifyNoOtherCalls(); } + + [Test] + public async Task GetCopyAuthorizationHeaderAsync() + { + CancellationToken cancellationToken = new(); + string expectedToken = "foo"; + AccessToken accessToken = new(expectedToken, DateTimeOffset.UtcNow); + + Mock tokenCred = new(); + tokenCred.Setup(t => t.GetTokenAsync(It.IsAny(), It.IsAny())) + .Returns(new ValueTask(Task.FromResult(accessToken))); + + ShareFileClient client = new(new Uri("https://example.file.core.windows.net/share/file"), tokenCred.Object); + ShareFileStorageResource resource = new(client); + + // Act - Get access token + HttpAuthorization authorization = await resource.GetCopyAuthorizationHeaderInternalAsync(cancellationToken); + + // Assert + Assert.That(authorization.Parameter, Is.EqualTo(expectedToken)); + tokenCred.Verify(t => t.GetTokenAsync(It.IsAny(), cancellationToken), Times.Once()); + tokenCred.VerifyNoOtherCalls(); + } + + [Test] + public async Task GetCopyAuthorizationHeaderAsync_NoOAuth() + { + ShareFileClient nonOAuthClient = new(new Uri("https://example.file.core.windows.net/share/file")); + ShareFileStorageResource resource = new(nonOAuthClient); + + Assert.That(await resource.GetCopyAuthorizationHeaderInternalAsync(), Is.Null); + } } } From 653e289a52908da14d7aedcd9e5d7b45cf42e33f Mon Sep 17 00:00:00 2001 From: Jocelyn Schreppler Date: Mon, 9 Oct 2023 16:05:44 -0400 Subject: [PATCH 4/7] small changes --- .../src/DataMovementSharesExtensions.cs | 2 +- .../Azure.Storage.DataMovement.Files.Shares/src/PathScanner.cs | 3 +++ .../src/ShareDirectoryStorageResourceContainer.cs | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/DataMovementSharesExtensions.cs b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/DataMovementSharesExtensions.cs index b838c46e5922..eca0c2ed3d99 100644 --- a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/DataMovementSharesExtensions.cs +++ b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/DataMovementSharesExtensions.cs @@ -41,7 +41,7 @@ internal static StorageResourceProperties ToStorageResourceProperties( copyStatusDescription: properties?.CopyStatusDescription, copyId: properties?.CopyId, copyProgress: properties?.CopyProgress, - copySource: new Uri(properties?.CopySource), + copySource: properties?.CopySource != null ? new Uri(properties?.CopySource) : null, contentLength: properties.ContentLength, contentType: properties?.ContentType, eTag: properties.ETag, diff --git a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/PathScanner.cs b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/PathScanner.cs index a40918eb2271..f5a84e19e24b 100644 --- a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/PathScanner.cs +++ b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/PathScanner.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Threading; @@ -13,6 +14,8 @@ namespace Azure.Storage.DataMovement.Files.Shares { internal class PathScanner { + public static Lazy Singleton { get; } = new Lazy(() => new PathScanner()); + public virtual async IAsyncEnumerable ScanFilesAsync( ShareDirectoryClient directory, [EnumeratorCancellation] CancellationToken cancellationToken) diff --git a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareDirectoryStorageResourceContainer.cs b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareDirectoryStorageResourceContainer.cs index 161024ebb0fa..f448de6b17f7 100644 --- a/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareDirectoryStorageResourceContainer.cs +++ b/sdk/storage/Azure.Storage.DataMovement.Files.Shares/src/ShareDirectoryStorageResourceContainer.cs @@ -14,7 +14,7 @@ namespace Azure.Storage.DataMovement.Files.Shares internal class ShareDirectoryStorageResourceContainer : StorageResourceContainerInternal { internal ShareFileStorageResourceOptions ResourceOptions { get; set; } - internal PathScanner PathScanner { get; set; } + internal PathScanner PathScanner { get; set; } = PathScanner.Singleton.Value; internal ShareDirectoryClient ShareDirectoryClient { get; } From 37d8b10edde9aed782e05b83c0cab85f77d1bdb1 Mon Sep 17 00:00:00 2001 From: Jocelyn Schreppler Date: Wed, 18 Oct 2023 16:39:06 -0400 Subject: [PATCH 5/7] rebased and adopted a rename from main --- sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs | 2 +- .../Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs | 2 +- sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs index 1427310d6313..2097a3f444ec 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs @@ -348,7 +348,7 @@ internal ShareClient( clientDiagnostics: new ClientDiagnostics(options), clientOptions: options) { - Audience = options.Audience ?? ShareAudience.PublicAudience, + Audience = options.Audience ?? ShareAudience.DefaultAudience, }; _shareRestClient = BuildShareRestClient(shareUri); } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs index a67c7249f5a1..fe7ec2acad9c 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs @@ -414,7 +414,7 @@ internal ShareDirectoryClient( clientDiagnostics: new ClientDiagnostics(options), clientOptions: options) { - Audience = options.Audience ?? ShareAudience.PublicAudience, + Audience = options.Audience ?? ShareAudience.DefaultAudience, }; _directoryRestClient = BuildDirectoryRestClient(directoryUri); } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs index a00b0f72e56a..545c30db3ebf 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs @@ -424,7 +424,7 @@ internal ShareFileClient( clientDiagnostics: new ClientDiagnostics(options), clientOptions: options) { - Audience = options.Audience ?? ShareAudience.PublicAudience, + Audience = options.Audience ?? ShareAudience.DefaultAudience, }; _fileRestClient = BuildFileRestClient(fileUri); } From 900635b267e7cf5e6378a4a7a033e1f72dca78bc Mon Sep 17 00:00:00 2001 From: Jocelyn Schreppler Date: Wed, 18 Oct 2023 16:52:45 -0400 Subject: [PATCH 6/7] fix --- .../Azure.Storage.Files.Shares/src/ShareServiceClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs index 96984c5807fd..4ab8331339c2 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs @@ -327,7 +327,7 @@ internal ShareServiceClient( clientDiagnostics: new ClientDiagnostics(options), clientOptions: options) { - Audience = options.Audience ?? ShareAudience.PublicAudience, + Audience = options.Audience ?? ShareAudience.DefaultAudience, }; _serviceRestClient = BuildServiceRestClient(); } From 51fd83e17728a62f13c99f594e1f412863399b15 Mon Sep 17 00:00:00 2001 From: Jocelyn Schreppler Date: Thu, 19 Oct 2023 15:08:02 -0400 Subject: [PATCH 7/7] exportapi --- .../api/Azure.Storage.Files.Shares.net6.0.cs | 1 + .../api/Azure.Storage.Files.Shares.netstandard2.0.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs index 327a672990a9..ad8a11ac99d9 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net6.0.cs @@ -250,6 +250,7 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent public virtual System.Threading.Tasks.Task> ForceCloseHandleAsync(string handleId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } + protected static System.Threading.Tasks.Task GetCopyAuthorizationHeaderAsync(Azure.Storage.Files.Shares.ShareFileClient client, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetHandles(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.AsyncPageable GetHandlesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Files.Shares.ShareClient GetParentShareClientCore() { throw null; } diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs index 327a672990a9..ad8a11ac99d9 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.netstandard2.0.cs @@ -250,6 +250,7 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent public virtual System.Threading.Tasks.Task> ForceCloseHandleAsync(string handleId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } + protected static System.Threading.Tasks.Task GetCopyAuthorizationHeaderAsync(Azure.Storage.Files.Shares.ShareFileClient client, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetHandles(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.AsyncPageable GetHandlesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } protected internal virtual Azure.Storage.Files.Shares.ShareClient GetParentShareClientCore() { throw null; }