Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datamovement shares oauth #39164

Merged
merged 7 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -13,6 +14,8 @@ namespace Azure.Storage.DataMovement.Files.Shares
{
internal class PathScanner
{
public static Lazy<PathScanner> Singleton { get; } = new Lazy<PathScanner>(() => new PathScanner());

public virtual async IAsyncEnumerable<ShareFileClient> ScanFilesAsync(
ShareDirectoryClient directory,
[EnumeratorCancellation] CancellationToken cancellationToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand Down
Original file line number Diff line number Diff line change
@@ -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<HttpAuthorization> GetCopyAuthorizationTokenAsync(
ShareFileClient client,
CancellationToken cancellationToken)
=> ShareFileClient.GetCopyAuthorizationHeaderAsync(client, cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -171,11 +172,9 @@ protected override async Task<bool> DeleteIfExistsAsync(CancellationToken cancel
return await ShareFileClient.DeleteIfExistsAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
}

protected override Task<HttpAuthorization> GetCopyAuthorizationHeaderAsync(CancellationToken cancellationToken = default)
protected override async Task<HttpAuthorization> 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<StorageResourceProperties> GetPropertiesAsync(CancellationToken cancellationToken = default)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -544,5 +546,37 @@ await TestHelper.AssertExpectedExceptionAsync<RequestFailedException>(
Times.Once());
mock.VerifyNoOtherCalls();
}

[Test]
public async Task GetCopyAuthorizationHeaderAsync()
{
CancellationToken cancellationToken = new();
string expectedToken = "foo";
AccessToken accessToken = new(expectedToken, DateTimeOffset.UtcNow);

Mock<TokenCredential> tokenCred = new();
tokenCred.Setup(t => t.GetTokenAsync(It.IsAny<TokenRequestContext>(), It.IsAny<CancellationToken>()))
.Returns(new ValueTask<AccessToken>(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<TokenRequestContext>(), 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Storage.Files.Shares.Models.CloseHandlesResult>> 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<Azure.HttpAuthorization> GetCopyAuthorizationHeaderAsync(Azure.Storage.Files.Shares.ShareFileClient client, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.Pageable<Azure.Storage.Files.Shares.Models.ShareFileHandle> GetHandles(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.AsyncPageable<Azure.Storage.Files.Shares.Models.ShareFileHandle> GetHandlesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
protected internal virtual Azure.Storage.Files.Shares.ShareClient GetParentShareClientCore() { throw null; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent
public virtual System.Threading.Tasks.Task<Azure.Response<Azure.Storage.Files.Shares.Models.CloseHandlesResult>> 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<Azure.HttpAuthorization> GetCopyAuthorizationHeaderAsync(Azure.Storage.Files.Shares.ShareFileClient client, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.Pageable<Azure.Storage.Files.Shares.Models.ShareFileHandle> GetHandles(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.AsyncPageable<Azure.Storage.Files.Shares.Models.ShareFileHandle> GetHandlesAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
protected internal virtual Azure.Storage.Files.Shares.ShareClient GetParentShareClientCore() { throw null; }
Expand Down
5 changes: 4 additions & 1 deletion sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,10 @@ internal ShareClient(
sasCredential: sasCredential,
tokenCredential: tokenCredential,
clientDiagnostics: new ClientDiagnostics(options),
clientOptions: options);
clientOptions: options)
{
Audience = options.Audience ?? ShareAudience.DefaultAudience,
};
_shareRestClient = BuildShareRestClient(shareUri);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ internal class ShareClientConfiguration : StorageClientConfiguration

public TransferValidationOptions TransferValidation { get; internal set; }

public ShareAudience Audience { get; internal set; }
amnguye marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Create a <see cref="ShareClientConfiguration"/> with shared key authentication.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,10 @@ internal ShareDirectoryClient(
sasCredential: sasCredential,
tokenCredential: tokenCredential,
clientDiagnostics: new ClientDiagnostics(options),
clientOptions: options);
clientOptions: options)
{
Audience = options.Audience ?? ShareAudience.DefaultAudience,
};
_directoryRestClient = BuildDirectoryRestClient(directoryUri);
}

Expand Down
37 changes: 36 additions & 1 deletion sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,10 @@ internal ShareFileClient(
sasCredential: sasCredential,
tokenCredential: tokenCredential,
clientDiagnostics: new ClientDiagnostics(options),
clientOptions: options);
clientOptions: options)
{
Audience = options.Audience ?? ShareAudience.DefaultAudience,
};
_fileRestClient = BuildFileRestClient(fileUri);
}

Expand Down Expand Up @@ -498,6 +501,38 @@ private void SetNameFieldsIfNull()
}
}

#region internal static accessors for Azure.Storage.DataMovement.Blobs
/// <summary>
/// Get a <see cref="ShareFileClient"/>'s <see cref="HttpAuthorization"/>
/// for passing the authorization when performing service to service copy
/// where OAuth is necessary to authenticate the source.
/// </summary>
/// <param name="client">
/// The storage client which to generate the
/// authorization header off of.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>The BlobServiceClient's HttpPipeline.</returns>
protected static async Task<HttpAuthorization> GetCopyAuthorizationHeaderAsync(
amnguye marked this conversation as resolved.
Show resolved Hide resolved
ShareFileClient client,
CancellationToken cancellationToken = default)
{
if (client.ClientConfiguration.TokenCredential != default)
{
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;
}
#endregion internal static accessors for Azure.Storage.DataMovement.Blobs

#region Create
/// <summary>
/// Creates a new file or replaces an existing file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,10 @@ internal ShareServiceClient(
sasCredential: sasCredential,
tokenCredential: tokenCredential,
clientDiagnostics: new ClientDiagnostics(options),
clientOptions: options);
clientOptions: options)
{
Audience = options.Audience ?? ShareAudience.DefaultAudience,
};
_serviceRestClient = BuildServiceRestClient();
}

Expand Down
Loading