From ae5989de36ea7452782a9ea842d2f00b08f41745 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 10:48:48 -0500 Subject: [PATCH 01/17] Added ShareServiceClient.GetUserDelegationKey --- .../src/Generated/DirectoryRestClient.cs | 2 +- .../src/Generated/FileRestClient.cs | 2 +- .../Generated/Models/KeyInfo.Serialization.cs | 31 +++ .../src/Generated/Models/KeyInfo.cs | 40 ++++ .../Models/UserDelegationKey.Serialization.cs | 63 ++++++ .../src/Generated/Models/UserDelegationKey.cs | 57 ++++++ .../ServiceGetUserDelegationKeyHeaders.cs | 22 ++ .../src/Generated/ServiceRestClient.cs | 90 ++++++++- .../src/Generated/ShareModelFactory.cs | 58 ++++++ .../src/Generated/ShareRestClient.cs | 2 +- .../src/Models/Internal/KeyInfo.cs | 9 + .../src/ShareServiceClient.cs | 188 ++++++++++++++++++ .../src/autorest.md | 2 +- 13 files changed, 561 insertions(+), 5 deletions(-) create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.Serialization.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceGetUserDelegationKeyHeaders.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Models/Internal/KeyInfo.cs diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs index b23a2b043df3..9c6903b63811 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/DirectoryRestClient.cs @@ -33,7 +33,7 @@ internal partial class DirectoryRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2025-11-05". + /// Specifies the version of the operation to use for this request. The default value is "2026-02-06". /// If true, the trailing dot will not be trimmed from the target URI. /// Valid value is backup. /// If true, the trailing dot will not be trimmed from the source URI. diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs index d27ff9185988..c710504865ea 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/FileRestClient.cs @@ -34,7 +34,7 @@ internal partial class FileRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2025-11-05". + /// Specifies the version of the operation to use for this request. The default value is "2026-02-06". /// Only update is supported: - Update: Writes the bytes downloaded from the source url into the specified range. The default value is "update". /// If true, the trailing dot will not be trimmed from the target URI. /// Valid value is backup. diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.Serialization.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.Serialization.cs new file mode 100644 index 000000000000..64f644f529db --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.Serialization.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Xml; +using Azure.Core; +using Azure.Storage.Common; + +namespace Azure.Storage.Files.Shares.Models +{ + internal partial class KeyInfo : IXmlSerializable + { + void IXmlSerializable.Write(XmlWriter writer, string nameHint) + { + writer.WriteStartElement(nameHint ?? "KeyInfo"); + if (Common.Optional.IsDefined(Start)) + { + writer.WriteStartElement("Start"); + writer.WriteValue(Start); + writer.WriteEndElement(); + } + writer.WriteStartElement("Expiry"); + writer.WriteValue(Expiry); + writer.WriteEndElement(); + writer.WriteEndElement(); + } + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.cs new file mode 100644 index 000000000000..12c2e558b1d0 --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/KeyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using Azure.Storage.Common; + +namespace Azure.Storage.Files.Shares.Models +{ + /// Key information. + internal partial class KeyInfo + { + /// Initializes a new instance of . + /// The date-time the key expires in ISO 8601 UTC time. + /// is null. + public KeyInfo(string expiry) + { + Argument.AssertNotNull(expiry, nameof(expiry)); + + Expiry = expiry; + } + + /// Initializes a new instance of . + /// The date-time the key is active in ISO 8601 UTC time. + /// The date-time the key expires in ISO 8601 UTC time. + internal KeyInfo(string start, string expiry) + { + Start = start; + Expiry = expiry; + } + + /// The date-time the key is active in ISO 8601 UTC time. + public string Start { get; set; } + /// The date-time the key expires in ISO 8601 UTC time. + public string Expiry { get; } + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs new file mode 100644 index 000000000000..0da391751eae --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Xml.Linq; +using Azure.Core; + +namespace Azure.Storage.Files.Shares.Models +{ + public partial class UserDelegationKey + { + internal static UserDelegationKey DeserializeUserDelegationKey(XElement element) + { + string signedOid = default; + string signedTid = default; + DateTimeOffset signedStart = default; + DateTimeOffset signedExpiry = default; + string signedService = default; + string signedVersion = default; + string value = default; + if (element.Element("SignedOid") is XElement signedOidElement) + { + signedOid = (string)signedOidElement; + } + if (element.Element("SignedTid") is XElement signedTidElement) + { + signedTid = (string)signedTidElement; + } + if (element.Element("SignedStart") is XElement signedStartElement) + { + signedStart = signedStartElement.GetDateTimeOffsetValue("O"); + } + if (element.Element("SignedExpiry") is XElement signedExpiryElement) + { + signedExpiry = signedExpiryElement.GetDateTimeOffsetValue("O"); + } + if (element.Element("SignedService") is XElement signedServiceElement) + { + signedService = (string)signedServiceElement; + } + if (element.Element("SignedVersion") is XElement signedVersionElement) + { + signedVersion = (string)signedVersionElement; + } + if (element.Element("Value") is XElement valueElement) + { + value = (string)valueElement; + } + return new UserDelegationKey( + signedOid, + signedTid, + signedStart, + signedExpiry, + signedService, + signedVersion, + value); + } + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs new file mode 100644 index 000000000000..4a8584d50c44 --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using Azure.Storage.Common; + +namespace Azure.Storage.Files.Shares.Models +{ + /// A user delegation key. + public partial class UserDelegationKey + { + /// Initializes a new instance of . + /// The Azure Active Directory object ID in GUID format. + /// The Azure Active Directory tenant ID in GUID format. + /// The date-time the key is active. + /// The date-time the key expires. + /// Abbreviation of the Azure Storage service that accepts the key. + /// The service version that created the key. + /// The key as a base64 string. + /// , , , or is null. + internal UserDelegationKey(string signedOid, string signedTid, DateTimeOffset signedStart, DateTimeOffset signedExpiry, string signedService, string signedVersion, string value) + { + Argument.AssertNotNull(signedOid, nameof(signedOid)); + Argument.AssertNotNull(signedTid, nameof(signedTid)); + Argument.AssertNotNull(signedService, nameof(signedService)); + Argument.AssertNotNull(signedVersion, nameof(signedVersion)); + Argument.AssertNotNull(value, nameof(value)); + + SignedOid = signedOid; + SignedTid = signedTid; + SignedStart = signedStart; + SignedExpiry = signedExpiry; + SignedService = signedService; + SignedVersion = signedVersion; + Value = value; + } + + /// The Azure Active Directory object ID in GUID format. + public string SignedOid { get; } + /// The Azure Active Directory tenant ID in GUID format. + public string SignedTid { get; } + /// The date-time the key is active. + public DateTimeOffset SignedStart { get; } + /// The date-time the key expires. + public DateTimeOffset SignedExpiry { get; } + /// Abbreviation of the Azure Storage service that accepts the key. + public string SignedService { get; } + /// The service version that created the key. + public string SignedVersion { get; } + /// The key as a base64 string. + public string Value { get; } + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceGetUserDelegationKeyHeaders.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceGetUserDelegationKeyHeaders.cs new file mode 100644 index 000000000000..6318c506bd67 --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceGetUserDelegationKeyHeaders.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using Azure.Core; + +namespace Azure.Storage.Files.Shares +{ + internal partial class ServiceGetUserDelegationKeyHeaders + { + private readonly Response _response; + public ServiceGetUserDelegationKeyHeaders(Response response) + { + _response = response; + } + /// Indicates the version of the Blob service used to execute the request. This header is returned for requests made against version 2009-09-19 and above. + public string Version => _response.Headers.TryGetValue("x-ms-version", out string value) ? value : null; + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs index ac65f39364c2..80204aafd81e 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ServiceRestClient.cs @@ -31,7 +31,7 @@ internal partial class ServiceRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2025-11-05". + /// Specifies the version of the operation to use for this request. The default value is "2026-02-06". /// Valid value is backup. /// , , or is null. public ServiceRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version, ShareTokenIntent? fileRequestIntent = null) @@ -290,6 +290,94 @@ public ResponseWithHeaders } } + internal HttpMessage CreateGetUserDelegationKeyRequest(KeyInfo keyInfo, int? timeout) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.AppendRaw(_url, false); + uri.AppendPath("/", false); + uri.AppendQuery("restype", "service", true); + uri.AppendQuery("comp", "userdelegationkey", true); + if (timeout != null) + { + uri.AppendQuery("timeout", timeout.Value, true); + } + request.Uri = uri; + request.Headers.Add("x-ms-version", _version); + request.Headers.Add("Accept", "application/xml"); + request.Headers.Add("Content-Type", "application/xml"); + var content = new XmlWriterContent(); + content.XmlWriter.WriteObjectValue(keyInfo, "KeyInfo"); + request.Content = content; + return message; + } + + /// Retrieves a user delegation key for the Queue service. This is only a valid operation when using bearer token authentication. + /// Key information. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://learn.microsoft.com/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations">Setting Timeouts for File Service Operations.</a>. + /// The cancellation token to use. + /// is null. + public async Task> GetUserDelegationKeyAsync(KeyInfo keyInfo, int? timeout = null, CancellationToken cancellationToken = default) + { + if (keyInfo == null) + { + throw new ArgumentNullException(nameof(keyInfo)); + } + + using var message = CreateGetUserDelegationKeyRequest(keyInfo, timeout); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + var headers = new ServiceGetUserDelegationKeyHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + { + UserDelegationKey value = default; + var document = XDocument.Load(message.Response.ContentStream, LoadOptions.PreserveWhitespace); + if (document.Element("UserDelegationKey") is XElement userDelegationKeyElement) + { + value = UserDelegationKey.DeserializeUserDelegationKey(userDelegationKeyElement); + } + return ResponseWithHeaders.FromValue(value, headers, message.Response); + } + default: + throw new RequestFailedException(message.Response); + } + } + + /// Retrieves a user delegation key for the Queue service. This is only a valid operation when using bearer token authentication. + /// Key information. + /// The timeout parameter is expressed in seconds. For more information, see <a href="https://learn.microsoft.com/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations">Setting Timeouts for File Service Operations.</a>. + /// The cancellation token to use. + /// is null. + public ResponseWithHeaders GetUserDelegationKey(KeyInfo keyInfo, int? timeout = null, CancellationToken cancellationToken = default) + { + if (keyInfo == null) + { + throw new ArgumentNullException(nameof(keyInfo)); + } + + using var message = CreateGetUserDelegationKeyRequest(keyInfo, timeout); + _pipeline.Send(message, cancellationToken); + var headers = new ServiceGetUserDelegationKeyHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + { + UserDelegationKey value = default; + var document = XDocument.Load(message.Response.ContentStream, LoadOptions.PreserveWhitespace); + if (document.Element("UserDelegationKey") is XElement userDelegationKeyElement) + { + value = UserDelegationKey.DeserializeUserDelegationKey(userDelegationKeyElement); + } + return ResponseWithHeaders.FromValue(value, headers, message.Response); + } + default: + throw new RequestFailedException(message.Response); + } + } + internal HttpMessage CreateListSharesSegmentNextPageRequest(string nextLink, string prefix, string marker, int? maxresults, IEnumerable include, int? timeout) { var message = _pipeline.CreateMessage(); diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs new file mode 100644 index 000000000000..4669c88dab40 --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; + +namespace Azure.Storage.Files.Shares.Models +{ + /// Model factory for models. + public static partial class ShareModelFactory + { + /// Initializes a new instance of . + /// The Azure Active Directory object ID in GUID format. + /// The Azure Active Directory tenant ID in GUID format. + /// The date-time the key is active. + /// The date-time the key expires. + /// Abbreviation of the Azure Storage service that accepts the key. + /// The service version that created the key. + /// The key as a base64 string. + /// , , , or is null. + /// A new instance for mocking. + public static UserDelegationKey UserDelegationKey(string signedOid = null, string signedTid = null, DateTimeOffset signedStart = default, DateTimeOffset signedExpiry = default, string signedService = null, string signedVersion = null, string value = null) + { + if (signedOid == null) + { + throw new ArgumentNullException(nameof(signedOid)); + } + if (signedTid == null) + { + throw new ArgumentNullException(nameof(signedTid)); + } + if (signedService == null) + { + throw new ArgumentNullException(nameof(signedService)); + } + if (signedVersion == null) + { + throw new ArgumentNullException(nameof(signedVersion)); + } + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + return new UserDelegationKey( + signedOid, + signedTid, + signedStart, + signedExpiry, + signedService, + signedVersion, + value); + } + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs index 246a81dce072..6c34f57e8854 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareRestClient.cs @@ -32,7 +32,7 @@ internal partial class ShareRestClient /// The handler for diagnostic messaging in the client. /// The HTTP pipeline for sending and receiving REST requests and responses. /// The URL of the service account, share, directory or file that is the target of the desired operation. - /// Specifies the version of the operation to use for this request. The default value is "2025-11-05". + /// Specifies the version of the operation to use for this request. The default value is "2026-02-06". /// Valid value is backup. /// , , or is null. public ShareRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, string url, string version, ShareTokenIntent? fileRequestIntent = null) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Models/Internal/KeyInfo.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Models/Internal/KeyInfo.cs new file mode 100644 index 000000000000..bc52f7b2ee06 --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Models/Internal/KeyInfo.cs @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.Storage.Files.Shares.Models +{ + internal partial class KeyInfo + { + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs index f4ee006c9d67..74b3a67e058f 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareServiceClient.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -1429,6 +1430,193 @@ private async Task> UndeleteShareInternal( } #endregion + #region GetUserDelegationKey + /// + /// The operation retrieves a + /// key that can be used to delegate Active Directory authorization to + /// shared access signatures created with . + /// + /// + /// Start time for the key's validity, with null indicating an + /// immediate start. The time should be specified in UTC. + /// + /// Note: If you set the start time to the current time, failures + /// might occur intermittently for the first few minutes. This is due to different + /// machines having slightly different current times (known as clock skew). + /// + /// + /// Expiration of the key's validity. The time should be specified + /// in UTC. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing + /// the service replication statistics. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// If multiple failures occur, an will be thrown, + /// containing each failure instance. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-blobs")] + public virtual Response GetUserDelegationKey( + DateTimeOffset? startsOn, + DateTimeOffset expiresOn, + CancellationToken cancellationToken = default) => + GetUserDelegationKeyInternal( + startsOn, + expiresOn, + false, // async + cancellationToken) + .EnsureCompleted(); + + /// + /// The operation retrieves a + /// key that can be used to delegate Active Directory authorization to + /// shared access signatures created with . + /// + /// + /// Start time for the key's validity, with null indicating an + /// immediate start. The time should be specified in UTC. + /// + /// Note: If you set the start time to the current time, failures + /// might occur intermittently for the first few minutes. This is due to different + /// machines having slightly different current times (known as clock skew). + /// + /// + /// Expiration of the key's validity. The time should be specified + /// in UTC. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// A describing + /// the service replication statistics. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// If multiple failures occur, an will be thrown, + /// containing each failure instance. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-blobs")] + public virtual async Task> GetUserDelegationKeyAsync( + DateTimeOffset? startsOn, + DateTimeOffset expiresOn, + CancellationToken cancellationToken = default) => + await GetUserDelegationKeyInternal( + startsOn, + expiresOn, + true, // async + cancellationToken) + .ConfigureAwait(false); + + /// + /// The operation retrieves a + /// key that can be used to delegate Active Directory authorization to + /// shared access signatures created with . + /// + /// + /// Start time for the key's validity, with null indicating an + /// immediate start. The time should be specified in UTC. + /// + /// Note: If you set the start time to the current time, failures + /// might occur intermittently for the first few minutes. This is due to different + /// machines having slightly different current times (known as clock skew). + /// + /// + /// Expiration of the key's validity. The time should be specified + /// in UTC. + /// + /// + /// Optional to propagate + /// notifications that the operation should be cancelled. + /// + /// + /// + /// A describing + /// the service replication statistics. + /// + /// + /// A will be thrown if + /// a failure occurs. + /// If multiple failures occur, an will be thrown, + /// containing each failure instance. + /// + private async Task> GetUserDelegationKeyInternal( + DateTimeOffset? startsOn, + DateTimeOffset expiresOn, + bool async, + CancellationToken cancellationToken) + { + using (ClientConfiguration.Pipeline.BeginLoggingScope(nameof(ShareServiceClient))) + { + ClientConfiguration.Pipeline.LogMethodEnter( + nameof(GetUserDelegationKeyInternal), + message: $"{nameof(startsOn)}: {startsOn}\n" + + $"{nameof(expiresOn)}: {expiresOn}"); + + DiagnosticScope scope = ClientConfiguration.ClientDiagnostics.CreateScope($"{nameof(ShareServiceClient)}.{nameof(GetUserDelegationKey)}"); + + try + { + scope.Start(); + + if (startsOn.HasValue && startsOn.Value.Offset != TimeSpan.Zero) + { + throw Errors.InvalidDateTimeUtc(nameof(startsOn)); + } + + if (expiresOn.Offset != TimeSpan.Zero) + { + throw Errors.InvalidDateTimeUtc(nameof(expiresOn)); + } + + KeyInfo keyInfo = new KeyInfo(expiresOn.ToString(Constants.Iso8601Format, CultureInfo.InvariantCulture)) + { + Start = startsOn?.ToString(Constants.Iso8601Format, CultureInfo.InvariantCulture) + }; + + ResponseWithHeaders response; + + if (async) + { + response = await ServiceRestClient.GetUserDelegationKeyAsync( + keyInfo: keyInfo, + cancellationToken: cancellationToken).ConfigureAwait(false); + } + else + { + response = ServiceRestClient.GetUserDelegationKey( + keyInfo: keyInfo, + cancellationToken: cancellationToken); + } + + return Response.FromValue( + response.Value, + response.GetRawResponse()); + } + catch (Exception ex) + { + ClientConfiguration.Pipeline.LogException(ex); + scope.Failed(ex); + throw; + } + finally + { + ClientConfiguration.Pipeline.LogMethodExit(nameof(GetUserDelegationKeyInternal)); + scope.Dispose(); + } + } + } + #endregion + #region GenerateSas /// /// The diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md b/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md index e159437b91c1..becfcfaeabb7 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md +++ b/sdk/storage/Azure.Storage.Files.Shares/src/autorest.md @@ -4,7 +4,7 @@ Run `dotnet build /t:GenerateCode` to generate code. ``` yaml input-file: - - https://raw.githubusercontent.com/Azure/azure-rest-api-specs/596d8d2a8c1c50bd6ebe60036143f4c4787fc816/specification/storage/data-plane/Microsoft.FileStorage/stable/2025-11-05/file.json + - Q:\src\azure-rest-api-specs\specification\storage\data-plane\Microsoft.FileStorage\stable\2026-02-06\file.json generation1-convenience-client: true # https://github.com/Azure/autorest/issues/4075 skip-semantics-validation: true From 90804634271a2ad02e48962e1d74874a573336ad Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 11:18:02 -0500 Subject: [PATCH 02/17] Tests --- .../Azure.Storage.Files.Shares/assets.json | 2 +- .../tests/ServiceClientTests.cs | 49 +++++++++++++++++++ .../tests/ShareClientTestFixtureAttribute.cs | 2 +- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/assets.json b/sdk/storage/Azure.Storage.Files.Shares/assets.json index ce1e5e627a5a..c68c7d33f156 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/assets.json +++ b/sdk/storage/Azure.Storage.Files.Shares/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Files.Shares", - "Tag": "net/storage/Azure.Storage.Files.Shares_8e80a47735" + "Tag": "net/storage/Azure.Storage.Files.Shares_28c8bd84d1" } diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs index 5d22b96ace97..bd48eac5cf1d 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ServiceClientTests.cs @@ -583,6 +583,55 @@ await TestHelper.AssertExpectedExceptionAsync( e => Assert.AreEqual(ShareErrorCode.ShareNotFound.ToString(), e.ErrorCode)); } + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task GetUserDelegationKey() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + DateTimeOffset startTime = Recording.UtcNow.AddMinutes(-5); + DateTimeOffset expiryTime = Recording.UtcNow.AddHours(1); + + // Act + Response response = await service.GetUserDelegationKeyAsync(startTime, expiryTime); + + // Assert + Assert.IsNotNull(response.Value); + } + + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task GetUserDelegationKey_Error() + { + // Arrange + ShareServiceClient service = SharesClientBuilder.GetServiceClient_SharedKey(); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + service.GetUserDelegationKeyAsync(startsOn: null, expiresOn: Recording.UtcNow.AddHours(1)), + e => Assert.AreEqual("AuthenticationFailed", e.ErrorCode)); + } + + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task GetUserDelegationKey_ArgumentException() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + service.GetUserDelegationKeyAsync( + startsOn: null, + // ensure the time used is not UTC, as DateTimeOffset.Now could actually be UTC based on OS settings + // Use a custom time zone so we aren't dependent on OS having specific standard time zone. + expiresOn: TimeZoneInfo.ConvertTime( + Recording.Now.AddHours(1), + TimeZoneInfo.CreateCustomTimeZone("Storage Test Custom Time Zone", TimeSpan.FromHours(-3), "CTZ", "CTZ"))), + e => Assert.AreEqual("expiresOn must be UTC", e.Message)); + ; + } + #region GenerateSasTests [RecordedTest] public void CanGenerateSas_ClientConstructors() diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs index 698356c67d1a..9b56a17576f6 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareClientTestFixtureAttribute.cs @@ -48,7 +48,7 @@ public ShareClientTestFixtureAttribute(params object[] additionalParameters) additionalParameters: additionalParameters) { RecordingServiceVersion = StorageVersionExtensions.MaxVersion; - LiveServiceVersions = new object[] { StorageVersionExtensions.LatestVersion, }; + LiveServiceVersions = new object[] { StorageVersionExtensions.MaxVersion, }; } } } From 016547a29f18df720fb335fd6d03a886161ca380 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 11:21:28 -0500 Subject: [PATCH 03/17] Export-API --- .../api/Azure.Storage.Files.Shares.net8.0.cs | 14 ++++++++++++++ .../Azure.Storage.Files.Shares.netstandard2.0.cs | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs index 5b2206d6b33a..ef30cff16d2a 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs @@ -443,6 +443,8 @@ public ShareServiceClient(System.Uri serviceUri, Azure.Storage.StorageSharedKeyC public virtual Azure.Storage.Files.Shares.ShareClient GetShareClient(string shareName) { throw null; } public virtual Azure.Pageable GetShares(Azure.Storage.Files.Shares.Models.ShareTraits traits = Azure.Storage.Files.Shares.Models.ShareTraits.None, Azure.Storage.Files.Shares.Models.ShareStates states = Azure.Storage.Files.Shares.Models.ShareStates.None, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.AsyncPageable GetSharesAsync(Azure.Storage.Files.Shares.Models.ShareTraits traits = Azure.Storage.Files.Shares.Models.ShareTraits.None, Azure.Storage.Files.Shares.Models.ShareStates states = Azure.Storage.Files.Shares.Models.ShareStates.None, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetUserDelegationKey(System.DateTimeOffset? startsOn, System.DateTimeOffset expiresOn, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetUserDelegationKeyAsync(System.DateTimeOffset? startsOn, System.DateTimeOffset expiresOn, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response SetProperties(Azure.Storage.Files.Shares.Models.ShareServiceProperties properties, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task SetPropertiesAsync(Azure.Storage.Files.Shares.Models.ShareServiceProperties properties, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response UndeleteShare(string deletedShareName, string deletedShareVersion, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -1253,6 +1255,7 @@ public static partial class ShareModelFactory [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed) { throw null; } public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed, int numberOfHandlesFailedToClose) { throw null; } + public static Azure.Storage.Files.Shares.Models.UserDelegationKey UserDelegationKey(string signedOid = null, string signedTid = null, System.DateTimeOffset signedStart = default(System.DateTimeOffset), System.DateTimeOffset signedExpiry = default(System.DateTimeOffset), string signedService = null, string signedVersion = null, string value = null) { throw null; } } public partial class ShareProperties { @@ -1414,6 +1417,17 @@ internal StorageClosedHandlesSegment() { } public int NumberOfHandlesClosed { get { throw null; } } public int NumberOfHandlesFailedToClose { get { throw null; } } } + public partial class UserDelegationKey + { + internal UserDelegationKey() { } + public System.DateTimeOffset SignedExpiry { get { throw null; } } + public string SignedOid { get { throw null; } } + public string SignedService { get { throw null; } } + public System.DateTimeOffset SignedStart { get { throw null; } } + public string SignedTid { get { throw null; } } + public string SignedVersion { get { throw null; } } + public string Value { get { throw null; } } + } } namespace Azure.Storage.Files.Shares.Specialized { 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 ae3d9f9d158a..a51415bb85e8 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 @@ -443,6 +443,8 @@ public ShareServiceClient(System.Uri serviceUri, Azure.Storage.StorageSharedKeyC public virtual Azure.Storage.Files.Shares.ShareClient GetShareClient(string shareName) { throw null; } public virtual Azure.Pageable GetShares(Azure.Storage.Files.Shares.Models.ShareTraits traits = Azure.Storage.Files.Shares.Models.ShareTraits.None, Azure.Storage.Files.Shares.Models.ShareStates states = Azure.Storage.Files.Shares.Models.ShareStates.None, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.AsyncPageable GetSharesAsync(Azure.Storage.Files.Shares.Models.ShareTraits traits = Azure.Storage.Files.Shares.Models.ShareTraits.None, Azure.Storage.Files.Shares.Models.ShareStates states = Azure.Storage.Files.Shares.Models.ShareStates.None, string prefix = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetUserDelegationKey(System.DateTimeOffset? startsOn, System.DateTimeOffset expiresOn, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetUserDelegationKeyAsync(System.DateTimeOffset? startsOn, System.DateTimeOffset expiresOn, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response SetProperties(Azure.Storage.Files.Shares.Models.ShareServiceProperties properties, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task SetPropertiesAsync(Azure.Storage.Files.Shares.Models.ShareServiceProperties properties, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response UndeleteShare(string deletedShareName, string deletedShareVersion, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -1252,6 +1254,7 @@ public static partial class ShareModelFactory [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed) { throw null; } public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed, int numberOfHandlesFailedToClose) { throw null; } + public static Azure.Storage.Files.Shares.Models.UserDelegationKey UserDelegationKey(string signedOid = null, string signedTid = null, System.DateTimeOffset signedStart = default(System.DateTimeOffset), System.DateTimeOffset signedExpiry = default(System.DateTimeOffset), string signedService = null, string signedVersion = null, string value = null) { throw null; } } public partial class ShareProperties { @@ -1413,6 +1416,17 @@ internal StorageClosedHandlesSegment() { } public int NumberOfHandlesClosed { get { throw null; } } public int NumberOfHandlesFailedToClose { get { throw null; } } } + public partial class UserDelegationKey + { + internal UserDelegationKey() { } + public System.DateTimeOffset SignedExpiry { get { throw null; } } + public string SignedOid { get { throw null; } } + public string SignedService { get { throw null; } } + public System.DateTimeOffset SignedStart { get { throw null; } } + public string SignedTid { get { throw null; } } + public string SignedVersion { get { throw null; } } + public string Value { get { throw null; } } + } } namespace Azure.Storage.Files.Shares.Specialized { From 736f794c9df169f0d0ba7fddf1665621c332cc5c Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 11:48:56 -0500 Subject: [PATCH 04/17] Added ShareQueryParameters --- .../Shared/SasQueryParametersExtensions.cs | 2 + .../src/Azure.Storage.Files.Shares.csproj | 2 + .../Models/UserDelegationKey.Serialization.cs | 24 +-- .../src/Generated/Models/UserDelegationKey.cs | 39 ++--- .../src/Generated/ShareModelFactory.cs | 58 ------- .../src/Models/UserDelegationKey.cs | 58 +++++++ .../src/Sas/ShareSasBuilder.cs | 110 +++++++++++++ .../src/Sas/ShareSasQueryParameters.cs | 148 ++++++++++++++++++ 8 files changed, 344 insertions(+), 97 deletions(-) delete mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Models/UserDelegationKey.cs create mode 100644 sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasQueryParameters.cs diff --git a/sdk/storage/Azure.Storage.Common/src/Shared/SasQueryParametersExtensions.cs b/sdk/storage/Azure.Storage.Common/src/Shared/SasQueryParametersExtensions.cs index 0321d5c1ec6f..5b6155c08d7f 100644 --- a/sdk/storage/Azure.Storage.Common/src/Shared/SasQueryParametersExtensions.cs +++ b/sdk/storage/Azure.Storage.Common/src/Shared/SasQueryParametersExtensions.cs @@ -28,6 +28,8 @@ internal static void ParseKeyProperties( DataLakeSasQueryParameters #elif QueueSDK QueueSasQueryParameters +#elif FileSDK + ShareSasQueryParameters #endif parameters, IDictionary values) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj index 5370f3694692..b7f93d97d501 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj @@ -93,5 +93,7 @@ + + diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs index 0da391751eae..de60fc768eb9 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.Serialization.cs @@ -15,28 +15,28 @@ public partial class UserDelegationKey { internal static UserDelegationKey DeserializeUserDelegationKey(XElement element) { - string signedOid = default; - string signedTid = default; - DateTimeOffset signedStart = default; - DateTimeOffset signedExpiry = default; + string signedObjectId = default; + string signedTenantId = default; + DateTimeOffset signedStartsOn = default; + DateTimeOffset signedExpiresOn = default; string signedService = default; string signedVersion = default; string value = default; if (element.Element("SignedOid") is XElement signedOidElement) { - signedOid = (string)signedOidElement; + signedObjectId = (string)signedOidElement; } if (element.Element("SignedTid") is XElement signedTidElement) { - signedTid = (string)signedTidElement; + signedTenantId = (string)signedTidElement; } if (element.Element("SignedStart") is XElement signedStartElement) { - signedStart = signedStartElement.GetDateTimeOffsetValue("O"); + signedStartsOn = signedStartElement.GetDateTimeOffsetValue("O"); } if (element.Element("SignedExpiry") is XElement signedExpiryElement) { - signedExpiry = signedExpiryElement.GetDateTimeOffsetValue("O"); + signedExpiresOn = signedExpiryElement.GetDateTimeOffsetValue("O"); } if (element.Element("SignedService") is XElement signedServiceElement) { @@ -51,10 +51,10 @@ internal static UserDelegationKey DeserializeUserDelegationKey(XElement element) value = (string)valueElement; } return new UserDelegationKey( - signedOid, - signedTid, - signedStart, - signedExpiry, + signedObjectId, + signedTenantId, + signedStartsOn, + signedExpiresOn, signedService, signedVersion, value); diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs index 4a8584d50c44..64d8739370f6 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/Models/UserDelegationKey.cs @@ -14,44 +14,29 @@ namespace Azure.Storage.Files.Shares.Models public partial class UserDelegationKey { /// Initializes a new instance of . - /// The Azure Active Directory object ID in GUID format. - /// The Azure Active Directory tenant ID in GUID format. - /// The date-time the key is active. - /// The date-time the key expires. + /// The Azure Active Directory object ID in GUID format. + /// The Azure Active Directory tenant ID in GUID format. + /// The date-time the key is active. + /// The date-time the key expires. /// Abbreviation of the Azure Storage service that accepts the key. /// The service version that created the key. /// The key as a base64 string. - /// , , , or is null. - internal UserDelegationKey(string signedOid, string signedTid, DateTimeOffset signedStart, DateTimeOffset signedExpiry, string signedService, string signedVersion, string value) + /// , , , or is null. + internal UserDelegationKey(string signedObjectId, string signedTenantId, DateTimeOffset signedStartsOn, DateTimeOffset signedExpiresOn, string signedService, string signedVersion, string value) { - Argument.AssertNotNull(signedOid, nameof(signedOid)); - Argument.AssertNotNull(signedTid, nameof(signedTid)); + Argument.AssertNotNull(signedObjectId, nameof(signedObjectId)); + Argument.AssertNotNull(signedTenantId, nameof(signedTenantId)); Argument.AssertNotNull(signedService, nameof(signedService)); Argument.AssertNotNull(signedVersion, nameof(signedVersion)); Argument.AssertNotNull(value, nameof(value)); - SignedOid = signedOid; - SignedTid = signedTid; - SignedStart = signedStart; - SignedExpiry = signedExpiry; + SignedObjectId = signedObjectId; + SignedTenantId = signedTenantId; + SignedStartsOn = signedStartsOn; + SignedExpiresOn = signedExpiresOn; SignedService = signedService; SignedVersion = signedVersion; Value = value; } - - /// The Azure Active Directory object ID in GUID format. - public string SignedOid { get; } - /// The Azure Active Directory tenant ID in GUID format. - public string SignedTid { get; } - /// The date-time the key is active. - public DateTimeOffset SignedStart { get; } - /// The date-time the key expires. - public DateTimeOffset SignedExpiry { get; } - /// Abbreviation of the Azure Storage service that accepts the key. - public string SignedService { get; } - /// The service version that created the key. - public string SignedVersion { get; } - /// The key as a base64 string. - public string Value { get; } } } diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs deleted file mode 100644 index 4669c88dab40..000000000000 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Generated/ShareModelFactory.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -// - -#nullable disable - -using System; - -namespace Azure.Storage.Files.Shares.Models -{ - /// Model factory for models. - public static partial class ShareModelFactory - { - /// Initializes a new instance of . - /// The Azure Active Directory object ID in GUID format. - /// The Azure Active Directory tenant ID in GUID format. - /// The date-time the key is active. - /// The date-time the key expires. - /// Abbreviation of the Azure Storage service that accepts the key. - /// The service version that created the key. - /// The key as a base64 string. - /// , , , or is null. - /// A new instance for mocking. - public static UserDelegationKey UserDelegationKey(string signedOid = null, string signedTid = null, DateTimeOffset signedStart = default, DateTimeOffset signedExpiry = default, string signedService = null, string signedVersion = null, string value = null) - { - if (signedOid == null) - { - throw new ArgumentNullException(nameof(signedOid)); - } - if (signedTid == null) - { - throw new ArgumentNullException(nameof(signedTid)); - } - if (signedService == null) - { - throw new ArgumentNullException(nameof(signedService)); - } - if (signedVersion == null) - { - throw new ArgumentNullException(nameof(signedVersion)); - } - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - return new UserDelegationKey( - signedOid, - signedTid, - signedStart, - signedExpiry, - signedService, - signedVersion, - value); - } - } -} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Models/UserDelegationKey.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Models/UserDelegationKey.cs new file mode 100644 index 000000000000..db91b3323e2b --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Models/UserDelegationKey.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Core; + +namespace Azure.Storage.Files.Shares.Models +{ + /// + /// A user delegation key. + /// + public partial class UserDelegationKey + { + /// + /// The Azure Active Directory object ID in GUID format. + /// + [CodeGenMember("SignedOid")] + public string SignedObjectId { get; internal set; } + + /// + /// The Azure Active Directory tenant ID in GUID format. + /// + [CodeGenMember("SignedTid")] + public string SignedTenantId { get; internal set; } + + /// + /// The date-time the key expires. + /// + [CodeGenMember("SignedExpiry")] + public DateTimeOffset SignedExpiresOn { get; internal set; } + + /// + /// The date-time the key is active. + /// + [CodeGenMember("SignedStart")] + public DateTimeOffset SignedStartsOn { get; internal set; } + + /// + /// Abbreviation of the Azure Storage service that accepts the key. + /// + public string SignedService { get; internal set; } + + /// + /// The service version that created the key. + /// + public string SignedVersion { get; internal set; } + + /// + /// The key as a base64 string. + /// + public string Value { get; internal set; } + + /// + /// Constructor. + /// + internal UserDelegationKey() { } + } +} diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasBuilder.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasBuilder.cs index 441af08a50d7..8894dcf1f90b 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasBuilder.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasBuilder.cs @@ -7,6 +7,7 @@ using System.Text; using Azure.Core; using Azure.Storage.Files.Shares; +using Azure.Storage.Files.Shares.Models; namespace Azure.Storage.Sas { @@ -133,6 +134,13 @@ public class ShareSasBuilder /// public string ContentType { get; set; } + /// + /// Optional. Beginning in version 2025-07-05, this value specifies the Entra ID of the user would is authorized to + /// use the resulting SAS URL. The resulting SAS URL must be used in conjunction with an Entra ID token that has been + /// issued to the user specified in this value. + /// + public string DelegatedUserObjectId { get; set; } + /// /// Initializes a new instance of the /// class. @@ -352,6 +360,108 @@ private string ToStringToSign(StorageSharedKeyCredential sharedKeyCredential) ContentType); } + /// + /// Use an account's to sign this + /// shared access signature values to produce the proper SAS query + /// parameters for authenticating requests. + /// + /// + /// A returned from + /// . + /// + /// The name of the storage account. + /// + /// The used for authenticating requests. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-blobs")] + public ShareSasQueryParameters ToSasQueryParameters(UserDelegationKey userDelegationKey, string accountName) + => ToSasQueryParameters(userDelegationKey, accountName, out _); + + /// + /// Use an account's to sign this + /// shared access signature values to produce the proper SAS query + /// parameters for authenticating requests. + /// + /// + /// A returned from + /// . + /// + /// The name of the storage account. + /// + /// + /// For debugging purposes only. This string will be overwritten with the string to sign that was used to generate the . + /// + /// The used for authenticating requests. + /// + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-blobs")] + public ShareSasQueryParameters ToSasQueryParameters(UserDelegationKey userDelegationKey, string accountName, out string stringToSign) + { + userDelegationKey = userDelegationKey ?? throw Errors.ArgumentNull(nameof(userDelegationKey)); + + EnsureState(); + + stringToSign = ToStringToSign(userDelegationKey, accountName); + + string signature = SasExtensions.ComputeHMACSHA256(userDelegationKey.Value, stringToSign); + + ShareSasQueryParameters p = new ShareSasQueryParameters( + version: Version, + services: default, + resourceTypes: default, + protocol: Protocol, + startsOn: StartsOn, + expiresOn: ExpiresOn, + ipRange: IPRange, + identifier: null, + resource: Resource, + permissions: Permissions, + signature: signature, + keyOid: userDelegationKey.SignedObjectId, + keyTid: userDelegationKey.SignedTenantId, + keyStart: userDelegationKey.SignedStartsOn, + keyExpiry: userDelegationKey.SignedExpiresOn, + keyService: userDelegationKey.SignedService, + keyVersion: userDelegationKey.SignedVersion, + cacheControl: CacheControl, + contentDisposition: ContentDisposition, + contentEncoding: ContentEncoding, + contentLanguage: ContentLanguage, + contentType: ContentType, + delegatedUserObjectId: DelegatedUserObjectId); + return p; + } + + private string ToStringToSign(UserDelegationKey userDelegationKey, string accountName) + { + string startTime = SasExtensions.FormatTimesForSasSigning(StartsOn); + string expiryTime = SasExtensions.FormatTimesForSasSigning(ExpiresOn); + string signedStart = SasExtensions.FormatTimesForSasSigning(userDelegationKey.SignedStartsOn); + string signedExpiry = SasExtensions.FormatTimesForSasSigning(userDelegationKey.SignedExpiresOn); + + // See http://msdn.microsoft.com/en-us/library/azure/dn140255.aspx + return string.Join("\n", + Permissions, + startTime, + expiryTime, + GetCanonicalName(accountName, ShareName ?? string.Empty, FilePath ?? string.Empty), + userDelegationKey.SignedObjectId, + userDelegationKey.SignedTenantId, + signedStart, + signedExpiry, + userDelegationKey.SignedService, + userDelegationKey.SignedVersion, + null, // SignedKeyDelegatedUserTenantId, will be added in a future release. + DelegatedUserObjectId, + IPRange.ToString(), + SasExtensions.ToProtocolString(Protocol), + Version, + CacheControl, + ContentDisposition, + ContentEncoding, + ContentLanguage, + ContentType); + } + /// /// Computes the canonical name for a share or file resource for SAS signing. /// Share: "/file/account/sharename" diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasQueryParameters.cs b/sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasQueryParameters.cs new file mode 100644 index 000000000000..812525e8ee32 --- /dev/null +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Sas/ShareSasQueryParameters.cs @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Azure.Storage.Sas +{ + /// + /// A object represents the components + /// that make up an Azure Storage Shared Access Signature's query + /// parameters. You can construct a new instance using + /// . + /// + /// For more information, + /// + /// Create a service SAS. + /// + public sealed class ShareSasQueryParameters : SasQueryParameters + { + internal UserDelegationKeyProperties KeyProperties { get; set; } + + /// + /// Gets the Azure Active Directory object ID in GUID format. + /// + public string KeyObjectId => KeyProperties?.ObjectId; + + /// + /// Gets the Azure Active Directory tenant ID in GUID format + /// + public string KeyTenantId => KeyProperties?.TenantId; + + /// + /// Gets the time at which the key becomes valid. + /// + public DateTimeOffset KeyStartsOn => KeyProperties == null ? default : KeyProperties.StartsOn; + + /// + /// Gets the time at which the key becomes expires. + /// + public DateTimeOffset KeyExpiresOn => KeyProperties == null ? default : KeyProperties.ExpiresOn; + + /// + /// Gets the Storage service that accepts the key. + /// + public string KeyService => KeyProperties?.Service; + + /// + /// Gets the Storage service version that created the key. + /// + public string KeyVersion => KeyProperties?.Version; + + internal ShareSasQueryParameters() : base() + { + } + + /// + /// Creates a new BlobSasQueryParameters instance. + /// + internal ShareSasQueryParameters( + string version, + AccountSasServices? services, + AccountSasResourceTypes? resourceTypes, + SasProtocol protocol, + DateTimeOffset startsOn, + DateTimeOffset expiresOn, + SasIPRange ipRange, + string identifier, + string resource, + string permissions, + string signature, + string keyOid = default, + string keyTid = default, + DateTimeOffset keyStart = default, + DateTimeOffset keyExpiry = default, + string keyService = default, + string keyVersion = default, + string cacheControl = default, + string contentDisposition = default, + string contentEncoding = default, + string contentLanguage = default, + string contentType = default, + string delegatedUserObjectId = default) + : base( + version, + services, + resourceTypes, + protocol, + startsOn, + expiresOn, + ipRange, + identifier, + resource, + permissions, + signature, + cacheControl, + contentDisposition, + contentEncoding, + contentLanguage, + contentType, + authorizedAadObjectId: null, + unauthorizedAadObjectId: null, + correlationId: null, + directoryDepth: null, + encryptionScope: null, + delegatedUserObjectId) + { + KeyProperties = new UserDelegationKeyProperties + { + ObjectId = keyOid, + TenantId = keyTid, + StartsOn = keyStart, + ExpiresOn = keyExpiry, + Service = keyService, + Version = keyVersion + }; + } + + /// + /// Creates a new instance of the + /// type based on the supplied query parameters . + /// All SAS-related query parameters will be removed from + /// . + /// + /// URI query parameters + internal ShareSasQueryParameters( + IDictionary values) + : base(values) + { + this.ParseKeyProperties(values); + } + + /// + /// Convert the SAS query parameters into a URL encoded query string. + /// + /// + /// A URL encoded query string representing the SAS. + /// + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + KeyProperties.AppendProperties(sb); + AppendProperties(sb); + return sb.ToString(); + } + } +} From f71515534950c52057548101d1dfd7de1a40941c Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 11:52:25 -0500 Subject: [PATCH 05/17] Export-API --- .../api/Azure.Storage.Files.Shares.net8.0.cs | 23 +++++++++++++++---- ...ure.Storage.Files.Shares.netstandard2.0.cs | 23 +++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs index ef30cff16d2a..0e816dde8eb0 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs @@ -1255,7 +1255,6 @@ public static partial class ShareModelFactory [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed) { throw null; } public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed, int numberOfHandlesFailedToClose) { throw null; } - public static Azure.Storage.Files.Shares.Models.UserDelegationKey UserDelegationKey(string signedOid = null, string signedTid = null, System.DateTimeOffset signedStart = default(System.DateTimeOffset), System.DateTimeOffset signedExpiry = default(System.DateTimeOffset), string signedService = null, string signedVersion = null, string value = null) { throw null; } } public partial class ShareProperties { @@ -1420,11 +1419,11 @@ internal StorageClosedHandlesSegment() { } public partial class UserDelegationKey { internal UserDelegationKey() { } - public System.DateTimeOffset SignedExpiry { get { throw null; } } - public string SignedOid { get { throw null; } } + public System.DateTimeOffset SignedExpiresOn { get { throw null; } } + public string SignedObjectId { get { throw null; } } public string SignedService { get { throw null; } } - public System.DateTimeOffset SignedStart { get { throw null; } } - public string SignedTid { get { throw null; } } + public System.DateTimeOffset SignedStartsOn { get { throw null; } } + public string SignedTenantId { get { throw null; } } public string SignedVersion { get { throw null; } } public string Value { get { throw null; } } } @@ -1503,6 +1502,7 @@ public ShareSasBuilder(Azure.Storage.Sas.ShareSasPermissions permissions, System public string ContentEncoding { get { throw null; } set { } } public string ContentLanguage { get { throw null; } set { } } public string ContentType { get { throw null; } set { } } + public string DelegatedUserObjectId { get { throw null; } set { } } public System.DateTimeOffset ExpiresOn { get { throw null; } set { } } public string FilePath { get { throw null; } set { } } public string Identifier { get { throw null; } set { } } @@ -1523,6 +1523,8 @@ public void SetPermissions(Azure.Storage.Sas.ShareFileSasPermissions permissions public void SetPermissions(Azure.Storage.Sas.ShareSasPermissions permissions) { } public void SetPermissions(string rawPermissions) { } public void SetPermissions(string rawPermissions, bool normalize = false) { } + public Azure.Storage.Sas.ShareSasQueryParameters ToSasQueryParameters(Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, string accountName) { throw null; } + public Azure.Storage.Sas.ShareSasQueryParameters ToSasQueryParameters(Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, string accountName, out string stringToSign) { throw null; } public Azure.Storage.Sas.SasQueryParameters ToSasQueryParameters(Azure.Storage.StorageSharedKeyCredential sharedKeyCredential) { throw null; } public Azure.Storage.Sas.SasQueryParameters ToSasQueryParameters(Azure.Storage.StorageSharedKeyCredential sharedKeyCredential, out string stringToSign) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] @@ -1538,6 +1540,17 @@ public enum ShareSasPermissions Delete = 8, List = 16, } + public sealed partial class ShareSasQueryParameters : Azure.Storage.Sas.SasQueryParameters + { + internal ShareSasQueryParameters() { } + public System.DateTimeOffset KeyExpiresOn { get { throw null; } } + public string KeyObjectId { get { throw null; } } + public string KeyService { get { throw null; } } + public System.DateTimeOffset KeyStartsOn { get { throw null; } } + public string KeyTenantId { get { throw null; } } + public string KeyVersion { get { throw null; } } + public override string ToString() { throw null; } + } } namespace Microsoft.Extensions.Azure { 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 a51415bb85e8..661ea428d61b 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 @@ -1254,7 +1254,6 @@ public static partial class ShareModelFactory [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed) { throw null; } public static Azure.Storage.Files.Shares.Models.StorageClosedHandlesSegment StorageClosedHandlesSegment(string marker, int numberOfHandlesClosed, int numberOfHandlesFailedToClose) { throw null; } - public static Azure.Storage.Files.Shares.Models.UserDelegationKey UserDelegationKey(string signedOid = null, string signedTid = null, System.DateTimeOffset signedStart = default(System.DateTimeOffset), System.DateTimeOffset signedExpiry = default(System.DateTimeOffset), string signedService = null, string signedVersion = null, string value = null) { throw null; } } public partial class ShareProperties { @@ -1419,11 +1418,11 @@ internal StorageClosedHandlesSegment() { } public partial class UserDelegationKey { internal UserDelegationKey() { } - public System.DateTimeOffset SignedExpiry { get { throw null; } } - public string SignedOid { get { throw null; } } + public System.DateTimeOffset SignedExpiresOn { get { throw null; } } + public string SignedObjectId { get { throw null; } } public string SignedService { get { throw null; } } - public System.DateTimeOffset SignedStart { get { throw null; } } - public string SignedTid { get { throw null; } } + public System.DateTimeOffset SignedStartsOn { get { throw null; } } + public string SignedTenantId { get { throw null; } } public string SignedVersion { get { throw null; } } public string Value { get { throw null; } } } @@ -1502,6 +1501,7 @@ public ShareSasBuilder(Azure.Storage.Sas.ShareSasPermissions permissions, System public string ContentEncoding { get { throw null; } set { } } public string ContentLanguage { get { throw null; } set { } } public string ContentType { get { throw null; } set { } } + public string DelegatedUserObjectId { get { throw null; } set { } } public System.DateTimeOffset ExpiresOn { get { throw null; } set { } } public string FilePath { get { throw null; } set { } } public string Identifier { get { throw null; } set { } } @@ -1522,6 +1522,8 @@ public void SetPermissions(Azure.Storage.Sas.ShareFileSasPermissions permissions public void SetPermissions(Azure.Storage.Sas.ShareSasPermissions permissions) { } public void SetPermissions(string rawPermissions) { } public void SetPermissions(string rawPermissions, bool normalize = false) { } + public Azure.Storage.Sas.ShareSasQueryParameters ToSasQueryParameters(Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, string accountName) { throw null; } + public Azure.Storage.Sas.ShareSasQueryParameters ToSasQueryParameters(Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, string accountName, out string stringToSign) { throw null; } public Azure.Storage.Sas.SasQueryParameters ToSasQueryParameters(Azure.Storage.StorageSharedKeyCredential sharedKeyCredential) { throw null; } public Azure.Storage.Sas.SasQueryParameters ToSasQueryParameters(Azure.Storage.StorageSharedKeyCredential sharedKeyCredential, out string stringToSign) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] @@ -1537,6 +1539,17 @@ public enum ShareSasPermissions Delete = 8, List = 16, } + public sealed partial class ShareSasQueryParameters : Azure.Storage.Sas.SasQueryParameters + { + internal ShareSasQueryParameters() { } + public System.DateTimeOffset KeyExpiresOn { get { throw null; } } + public string KeyObjectId { get { throw null; } } + public string KeyService { get { throw null; } } + public System.DateTimeOffset KeyStartsOn { get { throw null; } } + public string KeyTenantId { get { throw null; } } + public string KeyVersion { get { throw null; } } + public override string ToString() { throw null; } + } } namespace Microsoft.Extensions.Azure { From 8cad50b030c401917e87f7b10db4d74b6a1d11e9 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 12:03:09 -0500 Subject: [PATCH 06/17] Added ShareClient.GenerateUserDelegationSas methods --- .../src/Azure.Storage.Files.Shares.csproj | 1 + .../src/ShareClient.cs | 172 ++++++++++++++++++ 2 files changed, 173 insertions(+) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj index b7f93d97d501..f15614af8467 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj @@ -23,6 +23,7 @@ + diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs index 77fe835f5f6a..c2c71ee74dfa 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs @@ -4212,6 +4212,178 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi } #endregion + #region GenerateUserDelegationSas + /// + /// The + /// returns a representing a Share Service + /// Shared Access Signature (SAS) Uri based on the Client properties + /// and parameters passed. The SAS is signed by the user delegation key + /// that is 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-blobs")] + public virtual Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) => + GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); + + /// + /// The + /// returns a representing a Share Service + /// Shared Access Signature (SAS) Uri based on the Client properties + /// and parameters passed. The SAS is signed by the user delegation key + /// that is 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-blobs")] + public virtual Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => + GenerateUserDelegationSasUri(new ShareSasBuilder(permissions, expiresOn) { ShareName = Name }, userDelegationKey, out stringToSign); + + /// + /// The + /// returns a representing a Share Service + /// Shared Access Signature (SAS) Uri based on the Client properties + /// and builder passed. The SAS is signed by the user delegation key + /// that is 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-blobs")] + public virtual Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey) => + GenerateUserDelegationSasUri(builder, userDelegationKey, out _); + + /// + /// The + /// returns a representing a Share Service + /// Shared Access Signature (SAS) Uri based on the Client properties + /// and builder passed. The SAS is signed by the user delegation key + /// that is 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-blobs")] + public virtual Uri GenerateUserDelegationSasUri(ShareSasBuilder 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 origial BlobSasBuilder. + builder = ShareSasBuilder.DeepCopy(builder); + + SetBuilderAndValidate(builder); + if (string.IsNullOrEmpty(AccountName)) + { + throw Errors.SasClientMissingData(nameof(AccountName)); + } + + ShareUriBuilder sasUri = new ShareUriBuilder(Uri) + { + Sas = builder.ToSasQueryParameters(userDelegationKey, AccountName, out stringToSign) + }; + return sasUri.ToUri(); + } + + private void SetBuilderAndValidate(ShareSasBuilder builder) + { + // Assign builder's ShareName if it is null. + builder.ShareName ??= Name; + + // Validate that builder is properly set + if (!builder.ShareName.Equals(Name, StringComparison.InvariantCulture)) + { + throw Errors.SasNamesNotMatching( + nameof(builder.ShareName), + nameof(ShareSasBuilder), + nameof(Name)); + } + if (!string.IsNullOrEmpty(builder.FilePath)) + { + throw Errors.SasBuilderEmptyParam( + nameof(builder), + nameof(builder.FilePath), + nameof(Constants.Blob.Container.Name)); + } + } + #endregion + #region GetParentClientCore private ShareServiceClient _parentShareServiceClient; From b3e14a7a21a32216400187c98989ac0f0cedc86e Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 12:16:11 -0500 Subject: [PATCH 07/17] Added DirectoryClient.GenerateUserDelegationSas methods --- .../src/Azure.Storage.Files.Shares.csproj | 1 - .../src/ShareClient.cs | 7 +- .../src/ShareDirectoryClient.cs | 164 ++++++++++++++++++ .../Azure.Storage.Files.Shares.Tests.csproj | 1 + 4 files changed, 168 insertions(+), 5 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj index f15614af8467..b7f93d97d501 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj +++ b/sdk/storage/Azure.Storage.Files.Shares/src/Azure.Storage.Files.Shares.csproj @@ -23,7 +23,6 @@ - diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs index c2c71ee74dfa..32ce29a48d5c 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs @@ -4363,10 +4363,9 @@ public virtual Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDel private void SetBuilderAndValidate(ShareSasBuilder builder) { - // Assign builder's ShareName if it is null. + // Assign builder's ShareName and Path, if they are null. builder.ShareName ??= Name; - // Validate that builder is properly set if (!builder.ShareName.Equals(Name, StringComparison.InvariantCulture)) { throw Errors.SasNamesNotMatching( @@ -4377,9 +4376,9 @@ private void SetBuilderAndValidate(ShareSasBuilder builder) if (!string.IsNullOrEmpty(builder.FilePath)) { throw Errors.SasBuilderEmptyParam( - nameof(builder), + nameof(builder), nameof(builder.FilePath), - nameof(Constants.Blob.Container.Name)); + nameof(Constants.File.Share.Name)); } } #endregion diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs index e4d034a81988..06a8a0c1ab31 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs @@ -3759,6 +3759,170 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi } #endregion + #region GenerateUserDelegationSas + /// + /// The + /// returns a that generates a Share 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. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a Share 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 Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => + GenerateUserDelegationSasUri(new ShareSasBuilder(permissions, expiresOn) + { + ShareName = ShareName, + FilePath = Path, + }, userDelegationKey, out stringToSign); + + /// + /// The + /// returns a that generates a Share 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 Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(builder, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a Share 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 Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey, out string stringToSign) + { + builder = builder ?? throw Errors.ArgumentNull(nameof(builder)); + + // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. + builder = ShareSasBuilder.DeepCopy(builder); + + SetBuilderAndValidate(builder); + + ShareUriBuilder sasUri = new ShareUriBuilder(Uri) + { + Sas = builder.ToSasQueryParameters(userDelegationKey, this.AccountName, out stringToSign) + }; + return sasUri.ToUri(); + } + + private void SetBuilderAndValidate(ShareSasBuilder builder) + { + // Assign builder's ShareName and Path, if they are null. + builder.ShareName ??= ShareName; + builder.FilePath ??= Path; + + if (!builder.ShareName.Equals(ShareName, StringComparison.InvariantCulture)) + { + throw Errors.SasNamesNotMatching( + nameof(builder.ShareName), + nameof(ShareSasBuilder), + nameof(ShareName)); + } + if (!builder.FilePath.Equals(Path, StringComparison.InvariantCulture)) + { + throw Errors.SasNamesNotMatching( + nameof(builder.FilePath), + nameof(ShareSasBuilder), + nameof(Path)); + } + } + #endregion + #region GetParentClientCore private ShareClient _parentShareClient; diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/Azure.Storage.Files.Shares.Tests.csproj b/sdk/storage/Azure.Storage.Files.Shares/tests/Azure.Storage.Files.Shares.Tests.csproj index 398a4b636748..3a6d542efdba 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/Azure.Storage.Files.Shares.Tests.csproj +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/Azure.Storage.Files.Shares.Tests.csproj @@ -10,6 +10,7 @@ + From bfb8c944e030229a994a59d555e180918738e0d5 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 12:26:12 -0500 Subject: [PATCH 08/17] Added FileClient.GenerateUserDelegationSas methods --- .../src/ShareClient.cs | 19 +-- .../src/ShareDirectoryClient.cs | 26 +-- .../src/ShareFileClient.cs | 160 +++++++++++++++++- 3 files changed, 161 insertions(+), 44 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs index 32ce29a48d5c..2ee82571315d 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareClient.cs @@ -4187,23 +4187,8 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. builder = ShareSasBuilder.DeepCopy(builder); - // Assign builder's ShareName and Path, if they are null. - builder.ShareName ??= Name; + SetBuilderAndValidate(builder); - if (!builder.ShareName.Equals(Name, StringComparison.InvariantCulture)) - { - throw Errors.SasNamesNotMatching( - nameof(builder.ShareName), - nameof(ShareSasBuilder), - nameof(Name)); - } - if (!string.IsNullOrEmpty(builder.FilePath)) - { - throw Errors.SasBuilderEmptyParam( - nameof(builder), - nameof(builder.FilePath), - nameof(Constants.File.Share.Name)); - } ShareUriBuilder sasUri = new ShareUriBuilder(Uri) { Query = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign).ToString() @@ -4360,6 +4345,7 @@ public virtual Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDel }; return sasUri.ToUri(); } + #endregion private void SetBuilderAndValidate(ShareSasBuilder builder) { @@ -4381,7 +4367,6 @@ private void SetBuilderAndValidate(ShareSasBuilder builder) nameof(Constants.File.Share.Name)); } } - #endregion #region GetParentClientCore diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs index 06a8a0c1ab31..a15ae2be5eb6 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs @@ -3733,24 +3733,8 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. builder = ShareSasBuilder.DeepCopy(builder); - // Assign builder's ShareName and Path, if they are null. - builder.ShareName ??= ShareName; - builder.FilePath ??= Path; + SetBuilderAndValidate(builder); - if (!builder.ShareName.Equals(ShareName, StringComparison.InvariantCulture)) - { - throw Errors.SasNamesNotMatching( - nameof(builder.ShareName), - nameof(ShareSasBuilder), - nameof(ShareName)); - } - if (!builder.FilePath.Equals(Path, StringComparison.InvariantCulture)) - { - throw Errors.SasNamesNotMatching( - nameof(builder.FilePath), - nameof(ShareSasBuilder), - nameof(Path)); - } ShareUriBuilder sasUri = new ShareUriBuilder(Uri) { Query = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign).ToString() @@ -3788,7 +3772,7 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi /// A will be thrown if a failure occurs. /// [EditorBrowsable(EditorBrowsableState.Never)] - [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); @@ -3823,7 +3807,7 @@ public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTim /// A will be thrown if a failure occurs. /// [EditorBrowsable(EditorBrowsableState.Never)] - [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => GenerateUserDelegationSasUri(new ShareSasBuilder(permissions, expiresOn) { @@ -3853,7 +3837,7 @@ public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTim /// /// A will be thrown if a failure occurs. /// - [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-datalake")] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] public Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey) => GenerateUserDelegationSasUri(builder, userDelegationKey, out _); @@ -3900,6 +3884,7 @@ public Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationK return sasUri.ToUri(); } + #endregion private void SetBuilderAndValidate(ShareSasBuilder builder) { // Assign builder's ShareName and Path, if they are null. @@ -3921,7 +3906,6 @@ private void SetBuilderAndValidate(ShareSasBuilder builder) nameof(Path)); } } - #endregion #region GetParentClientCore diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs index 240e861258ca..cd45a81424ed 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs @@ -7702,6 +7702,160 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi // Deep copy of builder so we don't modify the user's original ShareSasBuilder. builder = ShareSasBuilder.DeepCopy(builder); + SetBuilderAndValidate(builder); + + ShareUriBuilder sasUri = new ShareUriBuilder(Uri) + { + Query = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign).ToString() + }; + return sasUri.ToUri(); + } + #endregion + + #region GenerateUserDelegationSas + /// + /// The + /// returns a that generates a Share 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. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] + public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a Share 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-shares")] + public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => + GenerateUserDelegationSasUri(new ShareSasBuilder(permissions, expiresOn) + { + ShareName = ShareName, + FilePath = Path, + }, userDelegationKey, out stringToSign); + + /// + /// The + /// returns a that generates a Share 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-shares")] + public Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey) + => GenerateUserDelegationSasUri(builder, userDelegationKey, out _); + + /// + /// The + /// returns a that generates a Share File 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-shares")] + public Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey, out string stringToSign) + { + builder = builder ?? throw Errors.ArgumentNull(nameof(builder)); + + // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. + builder = ShareSasBuilder.DeepCopy(builder); + + SetBuilderAndValidate(builder); + + ShareUriBuilder sasUri = new ShareUriBuilder(Uri) + { + Sas = builder.ToSasQueryParameters(userDelegationKey, this.AccountName, out stringToSign) + }; + return sasUri.ToUri(); + } + #endregion + + private void SetBuilderAndValidate(ShareSasBuilder builder) + { // Assign builder's ShareName and Path, if they are null. builder.ShareName ??= ShareName; builder.FilePath ??= Path; @@ -7720,13 +7874,7 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi nameof(ShareSasBuilder), nameof(Path)); } - ShareUriBuilder sasUri = new ShareUriBuilder(Uri) - { - Query = builder.ToSasQueryParameters(ClientConfiguration.SharedKeyCredential, out stringToSign).ToString() - }; - return sasUri.ToUri(); } - #endregion #region GetParentClientCore From d95902db705a3eba943a008f88b3585a0e082908 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 12:27:33 -0500 Subject: [PATCH 09/17] Export-API --- .../api/Azure.Storage.Files.Shares.net8.0.cs | 20 +++++++++++++++++++ ...ure.Storage.Files.Shares.netstandard2.0.cs | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs index 0e816dde8eb0..d99df657bbfb 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs @@ -68,6 +68,12 @@ public ShareClient(System.Uri shareUri, Azure.Storage.StorageSharedKeyCredential public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Response> GetAccessPolicy(Azure.Storage.Files.Shares.Models.ShareFileRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual Azure.Response> GetAccessPolicy(System.Threading.CancellationToken cancellationToken) { throw null; } @@ -220,6 +226,13 @@ public ShareDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageShared public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Storage.Files.Shares.ShareFileClient GetFileClient(string fileName) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(Azure.Storage.Files.Shares.Models.ShareDirectoryGetFilesAndDirectoriesOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(string prefix, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -311,6 +324,13 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { 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; } 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 661ea428d61b..a2fa2d7ad304 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 @@ -68,6 +68,12 @@ public ShareClient(System.Uri shareUri, Azure.Storage.StorageSharedKeyCredential public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public virtual System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Response> GetAccessPolicy(Azure.Storage.Files.Shares.Models.ShareFileRequestConditions conditions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual Azure.Response> GetAccessPolicy(System.Threading.CancellationToken cancellationToken) { throw null; } @@ -220,6 +226,13 @@ public ShareDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageShared public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Storage.Files.Shares.ShareFileClient GetFileClient(string fileName) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(Azure.Storage.Files.Shares.Models.ShareDirectoryGetFilesAndDirectoriesOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(string prefix, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -311,6 +324,13 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { 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; } From 2dd684a09382fa4af4bb6573b8b0e50201afbe7f Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 12:39:48 -0500 Subject: [PATCH 10/17] Update --- .../src/ShareDirectoryClient.cs | 8 ++--- .../src/ShareFileClient.cs | 8 ++--- .../tests/ShareSasTests.cs | 29 +++++++++++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs index a15ae2be5eb6..3fe904d274da 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs @@ -3745,7 +3745,7 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi #region GenerateUserDelegationSas /// - /// The + /// The /// returns a that generates a Share 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. /// @@ -3773,11 +3773,11 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi /// [EditorBrowsable(EditorBrowsableState.Never)] [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] - public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) + public Uri GenerateUserDelegationSasUri(ShareFileSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); /// - /// The + /// The /// returns a that generates a Share 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. /// @@ -3808,7 +3808,7 @@ public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTim /// [EditorBrowsable(EditorBrowsableState.Never)] [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] - public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => + public Uri GenerateUserDelegationSasUri(ShareFileSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => GenerateUserDelegationSasUri(new ShareSasBuilder(permissions, expiresOn) { ShareName = ShareName, diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs index cd45a81424ed..17c965a9f70b 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareFileClient.cs @@ -7714,7 +7714,7 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi #region GenerateUserDelegationSas /// - /// The + /// The /// returns a that generates a Share 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. /// @@ -7742,11 +7742,11 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi /// [EditorBrowsable(EditorBrowsableState.Never)] [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] - public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) + public Uri GenerateUserDelegationSasUri(ShareFileSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); /// - /// The + /// The /// returns a that generates a Share 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. /// @@ -7777,7 +7777,7 @@ public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTim /// [EditorBrowsable(EditorBrowsableState.Never)] [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] - public Uri GenerateUserDelegationSasUri(ShareSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => + public Uri GenerateUserDelegationSasUri(ShareFileSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => GenerateUserDelegationSasUri(new ShareSasBuilder(permissions, expiresOn) { ShareName = ShareName, diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs index 45d67fc372ed..ac61c22ca08f 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs @@ -12,6 +12,7 @@ using Azure.Storage.Test.Shared; using Azure.Storage.Files.Shares.Specialized; using Azure.Storage.Files.Shares.Models; +using Azure.Storage.Sas; namespace Azure.Storage.Files.Shares.Tests { @@ -841,5 +842,33 @@ public async Task AccountSasPermissions_FileToLease() await InvokeAccountSasFileToLeaseTest(permissions: permissions); } #endregion + + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task ShareClient_GetUserDelegationSAS_Builder() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + await using DisposingShare test = await GetTestShareAsync(service); + ShareClient share = test.Share; + + Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( + startsOn: Recording.UtcNow.AddHours(-1), + expiresOn: Recording.UtcNow.AddHours(1)); + + ShareSasBuilder builder = new ShareSasBuilder( + permissions: ShareSasPermissions.All, + expiresOn: Recording.UtcNow.AddHours(1)); + + Uri sasUri = share.GenerateUserDelegationSasUri(builder, userDelegationKeyResponse.Value, out string stringToSign); + ShareClient sasShare = InstrumentClient(new ShareClient(sasUri, GetOptions())); + + // Act + Response propertiesResponse = await sasShare.GetPropertiesAsync(); + + // Assert + Assert.IsNotNull(propertiesResponse.Value.LastModified); + Assert.IsNotNull(stringToSign); + } } } From b43caedee601fd87a603c024aea1fd6f4289a155 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 12:48:02 -0500 Subject: [PATCH 11/17] Update --- .../tests/ShareSasTests.cs | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs index ac61c22ca08f..057aa273d405 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs @@ -843,6 +843,35 @@ public async Task AccountSasPermissions_FileToLease() } #endregion + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task ShareClient_GetUserDelegationSAS() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + await using DisposingShare test = await GetTestShareAsync(service); + ShareClient share = test.Share; + + Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( + startsOn: Recording.UtcNow.AddHours(-1), + expiresOn: Recording.UtcNow.AddHours(1)); + + Uri sasUri = share.GenerateUserDelegationSasUri( + ShareSasPermissions.All, + expiresOn: Recording.UtcNow.AddHours(1), + userDelegationKeyResponse.Value, + out string stringToSign); + ShareClientOptions options = GetOptions(); + options.ShareTokenIntent = ShareTokenIntent.Backup; + ShareClient sasShare = InstrumentClient(new ShareClient(sasUri, options)); + + // Act + await sasShare.CreateDirectoryAsync(GetNewDirectoryName()); + + // Assert + Assert.IsNotNull(stringToSign); + } + [RecordedTest] [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] public async Task ShareClient_GetUserDelegationSAS_Builder() @@ -861,13 +890,14 @@ public async Task ShareClient_GetUserDelegationSAS_Builder() expiresOn: Recording.UtcNow.AddHours(1)); Uri sasUri = share.GenerateUserDelegationSasUri(builder, userDelegationKeyResponse.Value, out string stringToSign); - ShareClient sasShare = InstrumentClient(new ShareClient(sasUri, GetOptions())); + ShareClientOptions options = GetOptions(); + options.ShareTokenIntent = ShareTokenIntent.Backup; + ShareClient sasShare = InstrumentClient(new ShareClient(sasUri, options)); // Act - Response propertiesResponse = await sasShare.GetPropertiesAsync(); + await sasShare.CreateDirectoryAsync(GetNewDirectoryName()); // Assert - Assert.IsNotNull(propertiesResponse.Value.LastModified); Assert.IsNotNull(stringToSign); } } From dd8eafebe6387a60569a3007d3ad73e188df0f2d Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 13:05:43 -0500 Subject: [PATCH 12/17] Update --- .../tests/ShareSasTests.cs | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs index 057aa273d405..b55048a4fe7c 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs @@ -900,5 +900,95 @@ public async Task ShareClient_GetUserDelegationSAS_Builder() // Assert Assert.IsNotNull(stringToSign); } + + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task DirectoryClient_GetUserDelegationSAS() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + await using DisposingDirectory test = await SharesClientBuilder.GetTestDirectoryAsync(service); + ShareDirectoryClient directory = test.Directory; + + Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( + startsOn: Recording.UtcNow.AddHours(-1), + expiresOn: Recording.UtcNow.AddHours(1)); + + Uri sasUri = directory.GenerateUserDelegationSasUri( + ShareFileSasPermissions.All, + expiresOn: Recording.UtcNow.AddHours(1), + userDelegationKeyResponse.Value, + out string stringToSign); + ShareClientOptions options = GetOptions(); + options.ShareTokenIntent = ShareTokenIntent.Backup; + ShareDirectoryClient sasDirectory = InstrumentClient(new ShareDirectoryClient(sasUri, options)); + + // Act + await sasDirectory.GetPropertiesAsync(); + + // Assert + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task FileClient_GetUserDelegationSAS() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + await using DisposingFile test = await SharesClientBuilder.GetTestFileAsync(service); + ShareFileClient file = test.File; + + Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( + startsOn: Recording.UtcNow.AddHours(-1), + expiresOn: Recording.UtcNow.AddHours(1)); + + Uri sasUri = file.GenerateUserDelegationSasUri( + ShareFileSasPermissions.All, + expiresOn: Recording.UtcNow.AddHours(1), + userDelegationKeyResponse.Value, + out string stringToSign); + ShareClientOptions options = GetOptions(); + options.ShareTokenIntent = ShareTokenIntent.Backup; + ShareFileClient sasFile = InstrumentClient(new ShareFileClient(sasUri, options)); + + // Act + await sasFile.GetPropertiesAsync(); + + // Assert + Assert.IsNotNull(stringToSign); + } + + [RecordedTest] + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task FileClient_GetUserDelegationSAS_Builder() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + await using DisposingFile test = await SharesClientBuilder.GetTestFileAsync(service); + ShareFileClient file = test.File; + + Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( + startsOn: Recording.UtcNow.AddHours(-1), + expiresOn: Recording.UtcNow.AddHours(1)); + + ShareSasBuilder builder = new ShareSasBuilder( + permissions: ShareFileSasPermissions.All, + expiresOn: Recording.UtcNow.AddHours(1)); + + Uri sasUri = file.GenerateUserDelegationSasUri( + builder, + userDelegationKeyResponse.Value, + out string stringToSign); + ShareClientOptions options = GetOptions(); + options.ShareTokenIntent = ShareTokenIntent.Backup; + ShareFileClient sasFile = InstrumentClient(new ShareFileClient(sasUri, options)); + + // Act + await sasFile.GetPropertiesAsync(); + + // Assert + Assert.IsNotNull(stringToSign); + } } } From 4421a7780eb44dd780ea8e2f56dca8d75b5b5499 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 13:13:33 -0500 Subject: [PATCH 13/17] Update --- .../tests/ShareSasTests.cs | 112 +++++++++++++++++- 1 file changed, 108 insertions(+), 4 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs index b55048a4fe7c..d5d4094e913c 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs @@ -3,16 +3,20 @@ using System; using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; -using Azure.Storage.Files.Shares.Tests; +using Azure.Core; using Azure.Core.TestFramework; -using NUnit.Framework; -using Azure.Storage.Test.Shared; -using Azure.Storage.Files.Shares.Specialized; using Azure.Storage.Files.Shares.Models; +using Azure.Storage.Files.Shares.Specialized; +using Azure.Storage.Files.Shares.Tests; using Azure.Storage.Sas; +using Azure.Storage.Test; +using Azure.Storage.Test.Shared; +using NUnit.Framework; namespace Azure.Storage.Files.Shares.Tests { @@ -990,5 +994,105 @@ public async Task FileClient_GetUserDelegationSAS_Builder() // Assert Assert.IsNotNull(stringToSign); } + + [RecordedTest] + [LiveOnly] // Cannot record Entra ID token + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task ShareClient_UserDelegationSas_DelegatedObjectId() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + await using DisposingShare test = await GetTestShareAsync(service); + ShareClient share = test.Share; + + Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( + startsOn: Recording.UtcNow.AddHours(-1), + expiresOn: Recording.UtcNow.AddHours(1)); + + // We need to get the object ID from the token credential used to authenticate the request + TokenCredential tokenCredential = TestEnvironment.Credential; + AccessToken accessToken = await tokenCredential.GetTokenAsync( + new TokenRequestContext(Scopes), + CancellationToken.None); + + JwtSecurityToken jwtSecurityToken = new JwtSecurityTokenHandler().ReadJwtToken(accessToken.Token); + jwtSecurityToken.Payload.TryGetValue(Constants.Sas.ObjectId, out object objectId); + + ShareSasBuilder sasBuilder = new ShareSasBuilder( + permissions: ShareSasPermissions.All, + expiresOn: Recording.UtcNow.AddHours(1)) + { + ShareName = share.Name, + DelegatedUserObjectId = objectId?.ToString() + }; + + ShareSasQueryParameters sasQueryParameters = sasBuilder.ToSasQueryParameters(userDelegationKeyResponse.Value, service.AccountName); + + ShareUriBuilder shareUriBuilder = new ShareUriBuilder(share.Uri) + { + Sas = sasQueryParameters + }; + + Uri sasUri = shareUriBuilder.ToUri(); + + ShareClientOptions options = GetOptions(); + options.ShareTokenIntent = ShareTokenIntent.Backup; + ShareClient sasShare = InstrumentClient(new ShareClient(sasUri, TestEnvironment.Credential, options)); + + // Act + await sasShare.CreateDirectoryAsync(GetNewDirectoryName()); + } + + [RecordedTest] + [LiveOnly] // Cannot record Entra ID token + [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] + public async Task ShareClient_UserDelegationSas_DelegatedObjectId_Fail() + { + // Arrange + ShareServiceClient service = GetServiceClient_OAuth(); + await using DisposingShare test = await GetTestShareAsync(service); + ShareClient share = test.Share; + + Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( + startsOn: Recording.UtcNow.AddHours(-1), + expiresOn: Recording.UtcNow.AddHours(1)); + + // We need to get the object ID from the token credential used to authenticate the request + TokenCredential tokenCredential = TestEnvironment.Credential; + AccessToken accessToken = await tokenCredential.GetTokenAsync( + new TokenRequestContext(Scopes), + CancellationToken.None); + + JwtSecurityToken jwtSecurityToken = new JwtSecurityTokenHandler().ReadJwtToken(accessToken.Token); + jwtSecurityToken.Payload.TryGetValue(Constants.Sas.ObjectId, out object objectId); + + ShareSasBuilder sasBuilder = new ShareSasBuilder( + permissions: ShareSasPermissions.All, + expiresOn: Recording.UtcNow.AddHours(1)) + { + ShareName = share.Name, + DelegatedUserObjectId = objectId?.ToString() + }; + + ShareSasQueryParameters sasQueryParameters = sasBuilder.ToSasQueryParameters(userDelegationKeyResponse.Value, service.AccountName); + + ShareUriBuilder shareUriBuilder = new ShareUriBuilder(share.Uri) + { + Sas = sasQueryParameters + }; + + Uri sasUri = shareUriBuilder.ToUri(); + + ShareClientOptions options = GetOptions(); + options.ShareTokenIntent = ShareTokenIntent.Backup; + + // We are deliberately not using the token credential to cause an auth failure + ShareClient sasShare = InstrumentClient(new ShareClient(sasUri, options)); + + // Act + await TestHelper.AssertExpectedExceptionAsync( + sasShare.CreateDirectoryAsync(GetNewDirectoryName()), + e => Assert.AreEqual("AuthenticationFailed", e.ErrorCode)); + } } } From 4a9e8bd64291846ee98da34ca6063f72f353bb67 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 14:23:43 -0500 Subject: [PATCH 14/17] Update --- .../tests/FileSasBuilderTests.cs | 118 +++++++++++++++++- 1 file changed, 115 insertions(+), 3 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/FileSasBuilderTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/FileSasBuilderTests.cs index 5d0356fa9ca3..94c9404960c6 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/FileSasBuilderTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/FileSasBuilderTests.cs @@ -2,8 +2,11 @@ // Licensed under the MIT License. using System; +using System.Security.Cryptography; +using System.Text; using System.Threading.Tasks; using Azure.Core.TestFramework; +using Azure.Storage.Files.Shares.Models; using Azure.Storage.Sas; using Azure.Storage.Test; using NUnit.Framework; @@ -27,7 +30,7 @@ public void FileSasBuilder_ToSasQueryParameters_FilePathTest() var constants = TestConstants.Create(this); var shareName = GetNewShareName(); var filePath = GetNewDirectoryName(); - ShareSasBuilder fileSasBuilder = BuildFileSasBuilder(includeFilePath: true, constants, shareName, filePath); + ShareSasBuilder fileSasBuilder = BuildFileSasBuilder(includeFilePath: true, constants, shareName, filePath, includeDelegatedUserObjectId: false); var signature = BuildSignature(includeFilePath: true, constants, shareName, filePath); string stringToSign = null; @@ -58,7 +61,7 @@ public void FileSasBuilder_NullSharedKeyCredentialTest() var constants = TestConstants.Create(this); var shareName = GetNewShareName(); var filePath = GetNewDirectoryName(); - ShareSasBuilder fileSasBuilder = BuildFileSasBuilder(includeFilePath: true, constants, shareName, filePath); + ShareSasBuilder fileSasBuilder = BuildFileSasBuilder(includeFilePath: true, constants, shareName, filePath, includeDelegatedUserObjectId: false); // Act Assert.Throws(() => fileSasBuilder.ToSasQueryParameters(null), "sharedKeyCredential"); @@ -282,7 +285,56 @@ public async Task SasCredentialRequiresUriWithoutSasError_RedactedSasUri() Assert.IsFalse(ex.Message.Contains("sig=")); } - private ShareSasBuilder BuildFileSasBuilder(bool includeFilePath, TestConstants constants, string shareName, string filePath) + [RecordedTest] + public void ShareSasBuilder_ToSasQuerParameters_IdentitySas() + { + // Arrange + var constants = TestConstants.Create(this); + string shareName = GetNewShareName(); + string filePath = GetNewDirectoryName(); + ShareSasBuilder fileSasBuilder = BuildFileSasBuilder(includeFilePath: true, constants, shareName, filePath, includeDelegatedUserObjectId: true); + string signature = BuildUserDelegationSasSignature(includeFilePath: true, constants, shareName, filePath); + string stringToSign = null; + + // Act + ShareSasQueryParameters sasQueryParameters = fileSasBuilder.ToSasQueryParameters( + GetUserDelegationKey(constants), + constants.Sas.Account, + out stringToSign); + + // Assert + Assert.AreEqual(SasQueryParametersInternals.DefaultSasVersionInternal, sasQueryParameters.Version); + Assert.IsNull(sasQueryParameters.Services); + Assert.IsNull(sasQueryParameters.ResourceTypes); + Assert.AreEqual(constants.Sas.Protocol, sasQueryParameters.Protocol); + Assert.AreEqual(constants.Sas.StartTime, sasQueryParameters.StartsOn); + Assert.AreEqual(constants.Sas.ExpiryTime, sasQueryParameters.ExpiresOn); + Assert.AreEqual(constants.Sas.IPRange, sasQueryParameters.IPRange); + Assert.AreEqual(string.Empty, sasQueryParameters.Identifier); + Assert.AreEqual(constants.Sas.KeyObjectId, sasQueryParameters.KeyObjectId); + Assert.AreEqual(constants.Sas.KeyTenantId, sasQueryParameters.KeyTenantId); + Assert.AreEqual(constants.Sas.KeyStart, sasQueryParameters.KeyStartsOn); + Assert.AreEqual(constants.Sas.KeyExpiry, sasQueryParameters.KeyExpiresOn); + Assert.AreEqual(constants.Sas.KeyService, sasQueryParameters.KeyService); + Assert.AreEqual(constants.Sas.KeyVersion, sasQueryParameters.KeyVersion); + Assert.AreEqual(Constants.Sas.Resource.File, sasQueryParameters.Resource); + Assert.AreEqual(constants.Sas.CacheControl, sasQueryParameters.CacheControl); + Assert.AreEqual(constants.Sas.ContentDisposition, sasQueryParameters.ContentDisposition); + Assert.AreEqual(constants.Sas.ContentEncoding, sasQueryParameters.ContentEncoding); + Assert.AreEqual(constants.Sas.ContentLanguage, sasQueryParameters.ContentLanguage); + Assert.AreEqual(constants.Sas.ContentType, sasQueryParameters.ContentType); + Assert.AreEqual(Permissions, sasQueryParameters.Permissions); + Assert.AreEqual(constants.Sas.DelegatedObjectId, sasQueryParameters.DelegatedUserObjectId); + Assert.AreEqual(signature, sasQueryParameters.Signature); + Assert.IsNotNull(stringToSign); + } + + private ShareSasBuilder BuildFileSasBuilder( + bool includeFilePath, + TestConstants constants, + string shareName, + string filePath, + bool includeDelegatedUserObjectId) { var fileSasBuilder = new ShareSasBuilder { @@ -307,6 +359,11 @@ private ShareSasBuilder BuildFileSasBuilder(bool includeFilePath, TestConstants fileSasBuilder.FilePath = filePath; } + if (includeDelegatedUserObjectId) + { + fileSasBuilder.DelegatedUserObjectId = constants.Sas.DelegatedObjectId; + } + return fileSasBuilder; } @@ -335,5 +392,60 @@ private string BuildSignature(bool includeFilePath, TestConstants constants, str return StorageSharedKeyCredentialInternals.ComputeSasSignature(constants.Sas.SharedKeyCredential, stringToSign); } + + private string BuildUserDelegationSasSignature( + bool includeFilePath, + TestConstants constants, + string shareName, + string filePath) + { + string canonicalName = "/file/" + constants.Sas.Account + "/" + shareName; + if (includeFilePath) + { + canonicalName += "/" + filePath; + } + + string stringToSign = string.Join("\n", + Permissions, + SasExtensions.FormatTimesForSasSigning(constants.Sas.StartTime), + SasExtensions.FormatTimesForSasSigning(constants.Sas.ExpiryTime), + canonicalName, + constants.Sas.KeyObjectId, + constants.Sas.KeyTenantId, + SasExtensions.FormatTimesForSasSigning(constants.Sas.KeyStart), + SasExtensions.FormatTimesForSasSigning(constants.Sas.KeyExpiry), + constants.Sas.KeyService, + constants.Sas.KeyVersion, + null, + constants.Sas.DelegatedObjectId, + constants.Sas.IPRange.ToString(), + SasExtensions.ToProtocolString(constants.Sas.Protocol), + SasQueryParametersInternals.DefaultSasVersionInternal, + constants.Sas.CacheControl, + constants.Sas.ContentDisposition, + constants.Sas.ContentEncoding, + constants.Sas.ContentLanguage, + constants.Sas.ContentType); + + return ComputeHMACSHA256(constants.Sas.KeyValue, stringToSign); + } + + private string ComputeHMACSHA256(string userDelegationKeyValue, string message) => + Convert.ToBase64String( + new HMACSHA256( + Convert.FromBase64String(userDelegationKeyValue)) + .ComputeHash(Encoding.UTF8.GetBytes(message))); + + private static UserDelegationKey GetUserDelegationKey(TestConstants constants) + => new UserDelegationKey + { + SignedObjectId = constants.Sas.KeyObjectId, + SignedTenantId = constants.Sas.KeyTenantId, + SignedStartsOn = constants.Sas.KeyStart, + SignedExpiresOn = constants.Sas.KeyExpiry, + SignedService = constants.Sas.KeyService, + SignedVersion = constants.Sas.KeyVersion, + Value = constants.Sas.KeyValue + }; } } From ab18ab122fb3301fba286c0a059d6100e8ce78c1 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Fri, 20 Jun 2025 14:30:00 -0500 Subject: [PATCH 15/17] Recorded tests --- .../api/Azure.Storage.Files.Shares.net8.0.cs | 16 ++++++++-------- .../Azure.Storage.Files.Shares.netstandard2.0.cs | 16 ++++++++-------- .../Azure.Storage.Files.Shares/assets.json | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs index d99df657bbfb..fa581b48eb21 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs @@ -226,13 +226,13 @@ public ShareDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageShared public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Storage.Files.Shares.ShareFileClient GetFileClient(string fileName) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(Azure.Storage.Files.Shares.Models.ShareDirectoryGetFilesAndDirectoriesOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(string prefix, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -324,13 +324,13 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { 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; } 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 a2fa2d7ad304..d339096b499f 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 @@ -226,13 +226,13 @@ public ShareDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageShared public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Storage.Files.Shares.ShareFileClient GetFileClient(string fileName) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(Azure.Storage.Files.Shares.Models.ShareDirectoryGetFilesAndDirectoriesOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(string prefix, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } @@ -324,13 +324,13 @@ public ShareFileClient(System.Uri fileUri, Azure.Storage.StorageSharedKeyCredent public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } + public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { 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; } diff --git a/sdk/storage/Azure.Storage.Files.Shares/assets.json b/sdk/storage/Azure.Storage.Files.Shares/assets.json index c68c7d33f156..6eda6906d89d 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/assets.json +++ b/sdk/storage/Azure.Storage.Files.Shares/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "net", "TagPrefix": "net/storage/Azure.Storage.Files.Shares", - "Tag": "net/storage/Azure.Storage.Files.Shares_28c8bd84d1" + "Tag": "net/storage/Azure.Storage.Files.Shares_96ae58347c" } From 3048e851858cb6244d0030b720e4b2dccc8dc447 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Mon, 23 Jun 2025 13:37:31 -0500 Subject: [PATCH 16/17] Update --- .../src/ShareDirectoryClient.cs | 144 +----------------- .../tests/ShareSasTests.cs | 29 ---- 2 files changed, 2 insertions(+), 171 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs index 3fe904d274da..fdc8062f012c 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/src/ShareDirectoryClient.cs @@ -3627,6 +3627,7 @@ await GetFileClient(fileName) /// /// A will be thrown if a failure occurs. /// + [EditorBrowsable(EditorBrowsableState.Never)] [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] public virtual Uri GenerateSasUri(ShareFileSasPermissions permissions, DateTimeOffset expiresOn) => GenerateSasUri(permissions, expiresOn, out _); @@ -3694,6 +3695,7 @@ public virtual Uri GenerateSasUri(ShareFileSasPermissions permissions, DateTimeO /// /// A will be thrown if a failure occurs. /// + [EditorBrowsable(EditorBrowsableState.Never)] [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] public virtual Uri GenerateSasUri(ShareSasBuilder builder) => GenerateSasUri(builder, out _); @@ -3743,148 +3745,6 @@ public virtual Uri GenerateSasUri(ShareSasBuilder builder, out string stringToSi } #endregion - #region GenerateUserDelegationSas - /// - /// The - /// returns a that generates a Share 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. - /// - [EditorBrowsable(EditorBrowsableState.Never)] - [CallerShouldAudit("https://aka.ms/azsdk/callershouldaudit/storage-files-shares")] - public Uri GenerateUserDelegationSasUri(ShareFileSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey) - => GenerateUserDelegationSasUri(permissions, expiresOn, userDelegationKey, out _); - - /// - /// The - /// returns a that generates a Share 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-shares")] - public Uri GenerateUserDelegationSasUri(ShareFileSasPermissions permissions, DateTimeOffset expiresOn, UserDelegationKey userDelegationKey, out string stringToSign) => - GenerateUserDelegationSasUri(new ShareSasBuilder(permissions, expiresOn) - { - ShareName = ShareName, - FilePath = Path, - }, userDelegationKey, out stringToSign); - - /// - /// The - /// returns a that generates a Share 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-shares")] - public Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey) - => GenerateUserDelegationSasUri(builder, userDelegationKey, out _); - - /// - /// The - /// returns a that generates a Share 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 Uri GenerateUserDelegationSasUri(ShareSasBuilder builder, UserDelegationKey userDelegationKey, out string stringToSign) - { - builder = builder ?? throw Errors.ArgumentNull(nameof(builder)); - - // Deep copy of builder so we don't modify the user's original DataLakeSasBuilder. - builder = ShareSasBuilder.DeepCopy(builder); - - SetBuilderAndValidate(builder); - - ShareUriBuilder sasUri = new ShareUriBuilder(Uri) - { - Sas = builder.ToSasQueryParameters(userDelegationKey, this.AccountName, out stringToSign) - }; - return sasUri.ToUri(); - } - - #endregion private void SetBuilderAndValidate(ShareSasBuilder builder) { // Assign builder's ShareName and Path, if they are null. diff --git a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs index d5d4094e913c..a7322a26d9ad 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/tests/ShareSasTests.cs @@ -905,35 +905,6 @@ public async Task ShareClient_GetUserDelegationSAS_Builder() Assert.IsNotNull(stringToSign); } - [RecordedTest] - [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] - public async Task DirectoryClient_GetUserDelegationSAS() - { - // Arrange - ShareServiceClient service = GetServiceClient_OAuth(); - await using DisposingDirectory test = await SharesClientBuilder.GetTestDirectoryAsync(service); - ShareDirectoryClient directory = test.Directory; - - Response userDelegationKeyResponse = await service.GetUserDelegationKeyAsync( - startsOn: Recording.UtcNow.AddHours(-1), - expiresOn: Recording.UtcNow.AddHours(1)); - - Uri sasUri = directory.GenerateUserDelegationSasUri( - ShareFileSasPermissions.All, - expiresOn: Recording.UtcNow.AddHours(1), - userDelegationKeyResponse.Value, - out string stringToSign); - ShareClientOptions options = GetOptions(); - options.ShareTokenIntent = ShareTokenIntent.Backup; - ShareDirectoryClient sasDirectory = InstrumentClient(new ShareDirectoryClient(sasUri, options)); - - // Act - await sasDirectory.GetPropertiesAsync(); - - // Assert - Assert.IsNotNull(stringToSign); - } - [RecordedTest] [ServiceVersion(Min = ShareClientOptions.ServiceVersion.V2026_02_06)] public async Task FileClient_GetUserDelegationSAS() From 33bf2db39532526826935ccfb1bd64308f742e12 Mon Sep 17 00:00:00 2001 From: Sean McCullough Date: Mon, 23 Jun 2025 13:39:24 -0500 Subject: [PATCH 17/17] Export-API --- .../api/Azure.Storage.Files.Shares.net8.0.cs | 9 ++------- .../api/Azure.Storage.Files.Shares.netstandard2.0.cs | 9 ++------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs index fa581b48eb21..5e798d603ad5 100644 --- a/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs +++ b/sdk/storage/Azure.Storage.Files.Shares/api/Azure.Storage.Files.Shares.net8.0.cs @@ -220,19 +220,14 @@ public ShareDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageShared public virtual System.Threading.Tasks.Task ForceCloseAllHandlesAsync(bool? recursive = default(bool?), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response ForceCloseHandle(string handleId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> ForceCloseHandleAsync(string handleId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Storage.Files.Shares.ShareFileClient GetFileClient(string fileName) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(Azure.Storage.Files.Shares.Models.ShareDirectoryGetFilesAndDirectoriesOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(string prefix, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { 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 d339096b499f..d7f133409f37 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 @@ -220,19 +220,14 @@ public ShareDirectoryClient(System.Uri directoryUri, Azure.Storage.StorageShared public virtual System.Threading.Tasks.Task ForceCloseAllHandlesAsync(bool? recursive = default(bool?), System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Response ForceCloseHandle(string handleId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual System.Threading.Tasks.Task> ForceCloseHandleAsync(string handleId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, out string stringToSign) { throw null; } + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder) { throw null; } [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public virtual System.Uri GenerateSasUri(Azure.Storage.Sas.ShareSasBuilder builder, out string stringToSign) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareFileSasPermissions permissions, System.DateTimeOffset expiresOn, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey) { throw null; } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] - public System.Uri GenerateUserDelegationSasUri(Azure.Storage.Sas.ShareSasBuilder builder, Azure.Storage.Files.Shares.Models.UserDelegationKey userDelegationKey, out string stringToSign) { throw null; } public virtual Azure.Storage.Files.Shares.ShareFileClient GetFileClient(string fileName) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(Azure.Storage.Files.Shares.Models.ShareDirectoryGetFilesAndDirectoriesOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } public virtual Azure.Pageable GetFilesAndDirectories(string prefix, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }