From 7edd3036d26743abf44a16cc25cfc172b76ded5d Mon Sep 17 00:00:00 2001 From: Isabelle Date: Sun, 7 Dec 2025 12:12:11 -0800 Subject: [PATCH 01/37] wip implementation --- .../implementation/util/BlobSasImplUtil.java | 73 ++++++++++++------- .../sas/BlobServiceSasSignatureValues.java | 51 ++++++++++++- .../common/implementation/Constants.java | 11 +++ .../common/implementation/SasImplUtils.java | 34 +++++++++ .../common/sas/CommonSasQueryParameters.java | 34 +++++++++ .../util/DataLakeSasImplUtil.java | 70 +++++++++++------- .../DataLakeServiceSasSignatureValues.java | 48 ++++++++++++ 7 files changed, 266 insertions(+), 55 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java index 76803a1ed4b6..a24f2ab762bf 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java @@ -20,15 +20,17 @@ import com.azure.storage.common.sas.SasProtocol; import java.time.OffsetDateTime; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import static com.azure.storage.common.implementation.SasImplUtils.formatQueryParameterDate; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeadersForSasSigning; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParametersForSasSigning; import static com.azure.storage.common.implementation.SasImplUtils.tryAppendQueryParameter; /** * This class provides helper methods for common blob service sas patterns. - * * RESERVED FOR INTERNAL USE. */ public class BlobSasImplUtil { @@ -58,44 +60,27 @@ public class BlobSasImplUtil { .get(Constants.PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION, BlobServiceVersion.getLatest().getVersion()); private SasProtocol protocol; - private OffsetDateTime startTime; - private OffsetDateTime expiryTime; - private String permissions; - private SasIpRange sasIpRange; - private String containerName; - private String blobName; - private String resource; - private String snapshotId; - private String versionId; - private String identifier; - private String cacheControl; - private String contentDisposition; - private String contentEncoding; - private String contentLanguage; - private String contentType; - private String authorizedAadObjectId; - private String correlationId; - private String encryptionScope; - private String delegatedUserObjectId; + private Map requestHeaders; + private Map requestQueryParameters; /** * Creates a new {@link BlobSasImplUtil} with the specified parameters @@ -143,6 +128,8 @@ public BlobSasImplUtil(BlobServiceSasSignatureValues sasValues, String container this.correlationId = sasValues.getCorrelationId(); this.encryptionScope = encryptionScope; this.delegatedUserObjectId = sasValues.getDelegatedUserObjectId(); + this.requestHeaders = sasValues.getRequestHeaders(); + this.requestQueryParameters = sasValues.getRequestQueryParameters(); } /** @@ -272,6 +259,10 @@ private String encode(UserDelegationKey userDelegationKey, String signature) { tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_PERMISSIONS, this.permissions); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNATURE, signature); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_ENCRYPTION_SCOPE, this.encryptionScope); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_HEADERS, + formatRequestHeadersForSasSigning(this.requestHeaders)); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, + formatRequestQueryParametersForSasSigning(this.requestQueryParameters)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_ENCODING, this.contentEncoding); @@ -279,24 +270,23 @@ private String encode(UserDelegationKey userDelegationKey, String signature) { tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_TYPE, this.contentType); return sb.toString(); - } /** * Ensures that the builder's properties are in a consistent state. * - * 1. If there is no version, use latest. + *

1. If there is no version, use latest. * 2. If there is no identifier set, ensure expiryTime and permissions are set. * 3. Resource name is chosen by: * a. If "BlobName" is _not_ set, it is a container resource. * b. Otherwise, if "SnapshotId" is set, it is a blob snapshot resource. * c. Otherwise, if "VersionId" is set, it is a blob version resource. * d. Otherwise, it is a blob resource. - * 4. Reparse permissions depending on what the resource is. If it is an unrecognized resource, do nothing. + * 4. Reparse permissions depending on what the resource is. If it is an unrecognized resource, do nothing.

* * Taken from: - * https://github.com/Azure/azure-storage-blob-go/blob/master/azblob/sas_service.go#L33 - * https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/src/Sas/BlobSasBuilder.cs + * sas_service.go + * BlobSasBuilder.cs */ public void ensureState() { if (identifier == null) { @@ -443,6 +433,30 @@ private String stringToSign(final UserDelegationKey key, String canonicalName) { this.contentEncoding == null ? "" : this.contentEncoding, this.contentLanguage == null ? "" : this.contentLanguage, this.contentType == null ? "" : this.contentType); + } else if (VERSION.compareTo(BlobServiceVersion.V2026_02_06.getVersion()) <= 0) { + return String.join("\n", this.permissions == null ? "" : this.permissions, + this.startTime == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), + this.expiryTime == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), + canonicalName, key.getSignedObjectId() == null ? "" : key.getSignedObjectId(), + key.getSignedTenantId() == null ? "" : key.getSignedTenantId(), + key.getSignedStart() == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(key.getSignedStart()), + key.getSignedExpiry() == null + ? "" + : Constants.ISO_8601_UTC_DATE_FORMATTER.format(key.getSignedExpiry()), + key.getSignedService() == null ? "" : key.getSignedService(), + key.getSignedVersion() == null ? "" : key.getSignedVersion(), + this.authorizedAadObjectId == null ? "" : this.authorizedAadObjectId, + "", /* suoid - empty since this applies to HNS only accounts. */ + this.correlationId == null ? "" : this.correlationId, "", /* new schema 2025-07-05 */ + this.delegatedUserObjectId == null ? "" : this.delegatedUserObjectId, + this.sasIpRange == null ? "" : this.sasIpRange.toString(), + this.protocol == null ? "" : this.protocol.toString(), VERSION, resource, + versionSegment == null ? "" : versionSegment, this.encryptionScope == null ? "" : this.encryptionScope, + this.cacheControl == null ? "" : this.cacheControl, + this.contentDisposition == null ? "" : this.contentDisposition, + this.contentEncoding == null ? "" : this.contentEncoding, + this.contentLanguage == null ? "" : this.contentLanguage, + this.contentType == null ? "" : this.contentType); } else { return String.join("\n", this.permissions == null ? "" : this.permissions, this.startTime == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), @@ -462,6 +476,10 @@ private String stringToSign(final UserDelegationKey key, String canonicalName) { this.sasIpRange == null ? "" : this.sasIpRange.toString(), this.protocol == null ? "" : this.protocol.toString(), VERSION, resource, versionSegment == null ? "" : versionSegment, this.encryptionScope == null ? "" : this.encryptionScope, + this.requestHeaders == null ? "" : formatRequestHeadersForSasSigning(this.requestHeaders), + this.requestQueryParameters == null + ? "" + : formatRequestQueryParametersForSasSigning(this.requestQueryParameters), this.cacheControl == null ? "" : this.cacheControl, this.contentDisposition == null ? "" : this.contentDisposition, this.contentEncoding == null ? "" : this.contentEncoding, @@ -472,7 +490,8 @@ private String stringToSign(final UserDelegationKey key, String canonicalName) { /** * Gets the resource string for SAS token signing. - * @return + * + * @return The resource string. */ public String getResource() { return this.resource; @@ -480,7 +499,7 @@ public String getResource() { /** * Gets the permissions string for SAS token signing. - * @return + * @return The permissions string. */ public String getPermissions() { return this.permissions; diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java index 829bac396031..e57ce60a1303 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java @@ -16,6 +16,7 @@ import com.azure.storage.common.sas.SasProtocol; import java.time.OffsetDateTime; +import java.util.Map; /** * Used to initialize parameters for a Shared Access Signature (SAS) for an Azure Blob Storage service. Once all the @@ -83,6 +84,8 @@ public final class BlobServiceSasSignatureValues { private String correlationId; private String encryptionScope; private String delegatedUserObjectId; + private Map requestHeaders; + private Map requestQueryParameters; /** * Creates an object with empty values for all fields. @@ -600,6 +603,50 @@ public BlobServiceSasSignatureValues setDelegatedUserObjectId(String delegatedUs return this; } + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. + * Any usage of the SAS must include these headers and values in the request. + * + * @return The custom request headers to be set when the SAS is used. + */ + public Map getRequestHeaders() { + return requestHeaders; + } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. + * Any usage of the SAS must include these headers and values in the request. + * + * @param requestHeaders The custom request headers to be set when the SAS is used. + * @return the updated BlobServiceSasSignatureValues object + */ + public BlobServiceSasSignatureValues setRequestHeaders(Map requestHeaders) { + this.requestHeaders = requestHeaders; + return this; + } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in + * the SAS. Any usage of the SAS must include these query parameters and values in the request. + * + * @return The custom query parameters to be set when the SAS is used. + */ + public Map getRequestQueryParameters() { + return requestQueryParameters; + } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in + * the SAS. Any usage of the SAS must include these query parameters and values in the request. + * + * @param requestQueryParameters The custom query parameters to be set when the SAS is used. + * @return the updated BlobServiceSasSignatureValues object + */ + public BlobServiceSasSignatureValues setRequestQueryParameters(Map requestQueryParameters) { + this.requestQueryParameters = requestQueryParameters; + return this; + } + /** * Uses an account's shared key credential to sign these signature values to produce the proper SAS query * parameters. @@ -713,8 +760,8 @@ public BlobServiceSasQueryParameters generateSasQueryParameters(UserDelegationKe * 3. Reparse permissions depending on what the resource is. If it is an unrecognised resource, do nothing. *

* Taken from: - * https://github.com/Azure/azure-storage-blob-go/blob/master/azblob/sas_service.go#L33 - * https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/src/Sas/BlobSasBuilder.cs + * sas_service.go + * BlobSasBuilder.cs */ private void ensureState() { if (CoreUtils.isNullOrEmpty(blobName)) { diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java index 37105f3dff16..3d946dff8461 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java @@ -364,6 +364,17 @@ public static final class UrlConstants { */ public static final String SAS_ENCRYPTION_SCOPE = "ses"; + + /** + * The SAS request headers parameter. + */ + public static final String SAS_REQUEST_HEADERS = "srh"; + + /** + * The SAS request query parameters parameter. + */ + public static final String SAS_REQUEST_QUERY_PARAMETERS = "srq"; + /** * The SAS cache control parameter. */ diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java index 3f7713b09a63..e6717ff734ce 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java @@ -10,6 +10,7 @@ import com.azure.storage.common.policy.StorageSharedKeyCredentialPolicy; import java.util.Comparator; +import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.TreeMap; @@ -117,4 +118,37 @@ public static Map parseQueryString(String queryParams) { return retVals; } + + public static String formatRequestHeadersForSasSigning(Map requestHeaders) { + if (requestHeaders == null || requestHeaders.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + requestHeaders.forEach((key, value) -> sb.append(key).append(":").append(value).append("\n")); + return sb.toString(); + } + + public static String formatRequestQueryParametersForSasSigning(Map requestQueryParameters) { + if (requestQueryParameters == null || requestQueryParameters.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + requestQueryParameters.forEach((key, value) -> sb.append("\n").append(key).append(":").append(value)); + return sb.toString(); + } + + public static Map parseRequestHeadersAndQueryParameterString(String rawString) { + if (CoreUtils.isNullOrEmpty(rawString)) { + return null; + } + Map valueMap = new HashMap<>(); + String[] pairs = rawString.split("\n"); + for (String pair : pairs) { + if (!CoreUtils.isNullOrEmpty(pair)) { + String[] keyValue = pair.split(":", 2); + valueMap.put(keyValue[0].trim(), keyValue[1].trim()); + } + } + return valueMap; + } } diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java index f4a526e50212..b1e5f103e4e5 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java @@ -12,6 +12,9 @@ import java.util.Map; import java.util.function.Function; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeadersForSasSigning; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParametersForSasSigning; + /** * Represents the components that make up an Azure Storage SAS' query parameters. This type is not constructed directly * by the user; it is only generated by the URLParts type. NOTE: Instances of this class are immutable to ensure thread @@ -46,6 +49,8 @@ public class CommonSasQueryParameters { private final String correlationId; private final String encryptionScope; private final String delegatedUserObjectId; + private Map requestHeaders; + private Map requestQueryParameters; /** * Creates a new {@link CommonSasQueryParameters} object. @@ -111,6 +116,11 @@ public CommonSasQueryParameters(Map queryParamsMap, boolean re removeSasParametersFromMap); this.delegatedUserObjectId = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_DELEGATED_USER_OBJECT_ID, removeSasParametersFromMap); + this.requestHeaders = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_REQUEST_HEADERS, + removeSasParametersFromMap, SasImplUtils::parseRequestHeadersAndQueryParameterString); + this.requestQueryParameters + = getQueryParameter(queryParamsMap, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, + removeSasParametersFromMap, SasImplUtils::parseRequestHeadersAndQueryParameterString); } /** @@ -189,6 +199,10 @@ public String encode() { SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_KEY_SERVICE, this.keyService); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_KEY_VERSION, this.keyVersion); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_RESOURCE, this.resource); + SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_HEADERS, + formatRequestHeadersForSasSigning(this.requestHeaders)); + SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, + formatRequestQueryParametersForSasSigning(this.requestQueryParameters)); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); @@ -482,4 +496,24 @@ public String getEncryptionScope() { public String getDelegatedUserObjectId() { return delegatedUserObjectId; } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. + * Any usage of the SAS must include these headers and values in the request. + * + * @return A map of request headers. + */ + public Map getRequestHeaders() { + return requestHeaders; + } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in + * the SAS. Any usage of the SAS must include these query parameters and values in the request. + * + * @return A map of request query parameters. + */ + public Map getRequestQueryParameters() { + return requestQueryParameters; + } } diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java index e4b75d4e50c1..985080402296 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java @@ -20,10 +20,13 @@ import com.azure.storage.file.datalake.sas.PathSasPermission; import java.time.OffsetDateTime; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; import static com.azure.storage.common.implementation.SasImplUtils.formatQueryParameterDate; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeadersForSasSigning; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParametersForSasSigning; import static com.azure.storage.common.implementation.SasImplUtils.tryAppendQueryParameter; /** @@ -53,46 +56,28 @@ public class DataLakeSasImplUtil { .get(Constants.PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION, DataLakeServiceVersion.getLatest().getVersion()); private SasProtocol protocol; - private OffsetDateTime startTime; - private OffsetDateTime expiryTime; - private String permissions; - private SasIpRange sasIpRange; - private String fileSystemName; - private String pathName; - private String resource; - private String identifier; - private String cacheControl; - private String contentDisposition; - private String contentEncoding; - private String contentLanguage; - private String contentType; - private Boolean isDirectory; - private Integer directoryDepth; - private String authorizedAadObjectId; - private String unauthorizedAadObjectId; - private String correlationId; - private String encryptionScope; - private String delegatedUserObjectId; + private Map requestHeaders; + private Map requestQueryParameters; /** * Creates a new {@link DataLakeSasImplUtil} with the specified parameters @@ -134,6 +119,8 @@ public DataLakeSasImplUtil(DataLakeServiceSasSignatureValues sasValues, String f this.isDirectory = isDirectory; this.encryptionScope = sasValues.getEncryptionScope(); this.delegatedUserObjectId = sasValues.getDelegatedUserObjectId(); + this.requestHeaders = sasValues.getRequestHeaders(); + this.requestQueryParameters = sasValues.getRequestQueryParameters(); } /** @@ -270,20 +257,23 @@ private String encode(UserDelegationKey userDelegationKey, String signature) { } tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNATURE, signature); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_ENCRYPTION_SCOPE, this.encryptionScope); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_HEADERS, + formatRequestHeadersForSasSigning(this.requestHeaders)); + tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, + formatRequestQueryParametersForSasSigning(this.requestQueryParameters)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_ENCODING, this.contentEncoding); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_LANGUAGE, this.contentLanguage); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_TYPE, this.contentType); - tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_ENCRYPTION_SCOPE, this.encryptionScope); return sb.toString(); } /** - * Ensures that the builder's properties are in a consistent state. - + *

Ensures that the builder's properties are in a consistent state. * 1. If there is no identifier set, ensure expiryTime and permissions are set. * 2. Resource name is chosen by: * a. If "BlobName" is _not_ set, it is a container resource. @@ -291,11 +281,11 @@ private String encode(UserDelegationKey userDelegationKey, String signature) { * c. Otherwise, if "VersionId" is set, it is a blob version resource. * d. Otherwise, it is a blob resource. * 3. Reparse permissions depending on what the resource is. If it is an unrecognized resource, do nothing. - * 4. Ensure saoid is not set when suoid is set and vice versa. + * 4. Ensure saoid is not set when suoid is set and vice versa.

* * Taken from: - * https://github.com/Azure/azure-storage-blob-go/blob/master/azblob/sas_service.go#L33 - * https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/src/Sas/BlobSasBuilder.cs + * sas_service.go + * BlobSasBuilder.cs */ public void ensureState() { if (identifier == null) { @@ -445,6 +435,30 @@ public String stringToSign(final UserDelegationKey key, String canonicalName) { this.contentEncoding == null ? "" : this.contentEncoding, this.contentLanguage == null ? "" : this.contentLanguage, this.contentType == null ? "" : this.contentType); + } else if (VERSION.compareTo(DataLakeServiceVersion.V2026_02_06.getVersion()) <= 0) { + return String.join("\n", this.permissions == null ? "" : this.permissions, + this.startTime == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), + this.expiryTime == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(this.expiryTime), + canonicalName, key.getSignedObjectId() == null ? "" : key.getSignedObjectId(), + key.getSignedTenantId() == null ? "" : key.getSignedTenantId(), + key.getSignedStart() == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(key.getSignedStart()), + key.getSignedExpiry() == null + ? "" + : Constants.ISO_8601_UTC_DATE_FORMATTER.format(key.getSignedExpiry()), + key.getSignedService() == null ? "" : key.getSignedService(), + key.getSignedVersion() == null ? "" : key.getSignedVersion(), + this.authorizedAadObjectId == null ? "" : this.authorizedAadObjectId, + this.unauthorizedAadObjectId == null ? "" : this.unauthorizedAadObjectId, + this.correlationId == null ? "" : this.correlationId, "", /* new schema 2025-07-05 */ + this.delegatedUserObjectId == null ? "" : this.delegatedUserObjectId, + this.sasIpRange == null ? "" : this.sasIpRange.toString(), + this.protocol == null ? "" : this.protocol.toString(), VERSION, resource, "", /* Version segment. */ + this.encryptionScope == null ? "" : this.encryptionScope, + this.cacheControl == null ? "" : this.cacheControl, + this.contentDisposition == null ? "" : this.contentDisposition, + this.contentEncoding == null ? "" : this.contentEncoding, + this.contentLanguage == null ? "" : this.contentLanguage, + this.contentType == null ? "" : this.contentType); } else { return String.join("\n", this.permissions == null ? "" : this.permissions, this.startTime == null ? "" : Constants.ISO_8601_UTC_DATE_FORMATTER.format(this.startTime), @@ -464,6 +478,10 @@ public String stringToSign(final UserDelegationKey key, String canonicalName) { this.sasIpRange == null ? "" : this.sasIpRange.toString(), this.protocol == null ? "" : this.protocol.toString(), VERSION, resource, "", /* Version segment. */ this.encryptionScope == null ? "" : this.encryptionScope, + this.requestHeaders == null ? "" : formatRequestHeadersForSasSigning(this.requestHeaders), + this.requestQueryParameters == null + ? "" + : formatRequestQueryParametersForSasSigning(this.requestQueryParameters), this.cacheControl == null ? "" : this.cacheControl, this.contentDisposition == null ? "" : this.contentDisposition, this.contentEncoding == null ? "" : this.contentEncoding, diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java index abca896a2f00..54c90d3c04ba 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java @@ -4,6 +4,7 @@ package com.azure.storage.file.datalake.sas; import com.azure.core.util.Configuration; +import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.implementation.StorageImplUtils; import com.azure.storage.common.sas.SasIpRange; @@ -12,6 +13,7 @@ import com.azure.storage.file.datalake.models.UserDelegationKey; import java.time.OffsetDateTime; +import java.util.Map; /** * Used to initialize parameters for a Shared Access Signature (SAS) for an Azure Data Lake Storage service. Once all @@ -45,6 +47,8 @@ public final class DataLakeServiceSasSignatureValues { private String correlationId; private String encryptionScope; private String delegatedUserObjectId; + private Map requestHeaders; + private Map requestQueryParameters; /** * Creates an object with the specified expiry time and permissions @@ -475,4 +479,48 @@ public DataLakeServiceSasSignatureValues setDelegatedUserObjectId(String delegat this.delegatedUserObjectId = delegatedUserObjectId; return this; } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. + * Any usage of the SAS must include these headers and values in the request. + * + * @return The custom request headers to be set when the SAS is used. + */ + public Map getRequestHeaders() { + return requestHeaders; + } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. + * Any usage of the SAS must include these headers and values in the request. + * + * @param requestHeaders The custom request headers to be set when the SAS is used. + * @return the updated DataLakeServiceSasSignatureValues object + */ + public DataLakeServiceSasSignatureValues setRequestHeaders(Map requestHeaders) { + this.requestHeaders = requestHeaders; + return this; + } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in + * the SAS. Any usage of the SAS must include these query parameters and values in the request. + * + * @return The custom query parameters to be set when the SAS is used. + */ + public Map getRequestQueryParameters() { + return requestQueryParameters; + } + + /** + * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in + * the SAS. Any usage of the SAS must include these query parameters and values in the request. + * + * @param requestQueryParameters The custom query parameters to be set when the SAS is used. + * @return the updated DataLakeServiceSasSignatureValues object + */ + public DataLakeServiceSasSignatureValues setRequestQueryParameters(Map requestQueryParameters) { + this.requestQueryParameters = requestQueryParameters; + return this; + } } From 552074170afa56de448422f15bed8cb5d1d9d4a7 Mon Sep 17 00:00:00 2001 From: browndav Date: Tue, 20 Jan 2026 17:25:19 -0500 Subject: [PATCH 02/37] add base tests for SasImplUtilsTests --- .../implementation/SasImplUtilsTests.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java new file mode 100644 index 000000000000..425a7c0316de --- /dev/null +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -0,0 +1,53 @@ +package com.azure.storage.common.implementation; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals;; + +public class SasImplUtilsTests { + + private static Map requestHeaders; + + @BeforeEach + public void setup() { + requestHeaders = new HashMap<>(); + } + + @Test + public void formatRequestHeadersForSasSigningNullReturnsEmptyString() { + assertEquals("", SasImplUtils.formatRequestHeadersForSasSigning(null)); + } + + @Test + public void formatRequestHeadersForSasSigningEmptyReturnsEmptyString() { + assertEquals("", SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders)); + } + + @Test + public void formatRequestHeadersForSasSigningPopulatedHeaders() { + requestHeaders.put(Constants.HeaderConstants.ENCRYPTION_KEY, "encryptionKeyValue"); + requestHeaders.put(Constants.HeaderConstants.CONTENT_ENCODING, "contentEncodingValue"); + requestHeaders.put(Constants.HeaderConstants.CONTENT_TYPE, "contentTypeValue"); + requestHeaders.put(Constants.HeaderConstants.CLIENT_REQUEST_ID, "clientRequestId"); + + String expected = "x-ms-encryption-key:encryptionKeyValue\n" + "Content-Encoding:contentEncodingValue\n" + + "Content-Type:contentTypeValue\n" + "x-ms-client-request-id:clientRequestId\n"; + + String headers = SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders); + Integer newLineCount + = Arrays.stream(headers.split("")).filter(s -> s.equals("\n")).collect(Collectors.toList()).size(); + + String sortedExpected = Arrays.stream(expected.split("\n")).sorted().collect(Collectors.joining("\n")) + "\n"; + + String sortedHeaders = Arrays.stream(headers.split("\n")).sorted().collect(Collectors.joining("\n")) + "\n"; + + assertEquals(4, newLineCount); + assertEquals(sortedExpected, sortedHeaders); + } +} From 833e3e83ecbd407352fa74ca45e1d187bc43725a Mon Sep 17 00:00:00 2001 From: browndav Date: Tue, 20 Jan 2026 17:25:19 -0500 Subject: [PATCH 03/37] add base tests for SasImplUtilsTests --- .../implementation/SasImplUtilsTests.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java new file mode 100644 index 000000000000..425a7c0316de --- /dev/null +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -0,0 +1,53 @@ +package com.azure.storage.common.implementation; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals;; + +public class SasImplUtilsTests { + + private static Map requestHeaders; + + @BeforeEach + public void setup() { + requestHeaders = new HashMap<>(); + } + + @Test + public void formatRequestHeadersForSasSigningNullReturnsEmptyString() { + assertEquals("", SasImplUtils.formatRequestHeadersForSasSigning(null)); + } + + @Test + public void formatRequestHeadersForSasSigningEmptyReturnsEmptyString() { + assertEquals("", SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders)); + } + + @Test + public void formatRequestHeadersForSasSigningPopulatedHeaders() { + requestHeaders.put(Constants.HeaderConstants.ENCRYPTION_KEY, "encryptionKeyValue"); + requestHeaders.put(Constants.HeaderConstants.CONTENT_ENCODING, "contentEncodingValue"); + requestHeaders.put(Constants.HeaderConstants.CONTENT_TYPE, "contentTypeValue"); + requestHeaders.put(Constants.HeaderConstants.CLIENT_REQUEST_ID, "clientRequestId"); + + String expected = "x-ms-encryption-key:encryptionKeyValue\n" + "Content-Encoding:contentEncodingValue\n" + + "Content-Type:contentTypeValue\n" + "x-ms-client-request-id:clientRequestId\n"; + + String headers = SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders); + Integer newLineCount + = Arrays.stream(headers.split("")).filter(s -> s.equals("\n")).collect(Collectors.toList()).size(); + + String sortedExpected = Arrays.stream(expected.split("\n")).sorted().collect(Collectors.joining("\n")) + "\n"; + + String sortedHeaders = Arrays.stream(headers.split("\n")).sorted().collect(Collectors.joining("\n")) + "\n"; + + assertEquals(4, newLineCount); + assertEquals(sortedExpected, sortedHeaders); + } +} From 2c731da52f043ebe730c2536a0675cd08eacf1d1 Mon Sep 17 00:00:00 2001 From: browndav Date: Tue, 27 Jan 2026 11:32:44 -0500 Subject: [PATCH 04/37] revert changes to stringToSign from changes made based on api From 863b7b68c54029b11543fb5ab7572b2a1d5278d3 Mon Sep 17 00:00:00 2001 From: browndav Date: Tue, 27 Jan 2026 11:33:54 -0500 Subject: [PATCH 05/37] remove static from SasImplUtilsTests so that beforeeach works --- .../azure/storage/common/implementation/SasImplUtilsTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index 425a7c0316de..108bb8f31408 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -12,7 +12,7 @@ public class SasImplUtilsTests { - private static Map requestHeaders; + private Map requestHeaders; @BeforeEach public void setup() { From 28246fb8f3f9bae4c775f1c29d7cd985652b0214 Mon Sep 17 00:00:00 2001 From: browndav Date: Tue, 27 Jan 2026 18:31:51 -0500 Subject: [PATCH 06/37] add documentation for srq and srh --- .../common/implementation/SasImplUtils.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java index e6717ff734ce..17aa7ffc0d17 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java @@ -119,6 +119,17 @@ public static Map parseQueryString(String queryParams) { return retVals; } + /** + * Formats request headers for SAS signing. + * + * @param requestHeaders The map of request headers to format. + * @return A formatted string with headers in the format "key:value" separated by newlines, or empty string if + * null/empty. Terminates each pair with a newline (\n). + * @see + * + * Version 2026-04-06 and later (Blob Storage and Data Lake Storage) + */ + public static String formatRequestHeadersForSasSigning(Map requestHeaders) { if (requestHeaders == null || requestHeaders.isEmpty()) { return ""; @@ -128,6 +139,16 @@ public static String formatRequestHeadersForSasSigning(Map reque return sb.toString(); } + /** + * Formats request headers for SAS signing. + * + * @param requestQueryParameters The map of request headers to format. + * @return A formatted string with query params in the format "key:value" separated by newlines, or empty string if + * null/empty. Prepends a newline character. Prefixes each pair with a newline (\n). + * @see + * + * Version 2026-04-06 and later (Blob Storage and Data Lake Storage) + */ public static String formatRequestQueryParametersForSasSigning(Map requestQueryParameters) { if (requestQueryParameters == null || requestQueryParameters.isEmpty()) { return ""; From 05b118e49fd57b42b32cda95184e4d342261e858 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 28 Jan 2026 11:01:05 -0500 Subject: [PATCH 07/37] finish sasClientTests --- .../azure/storage/blob/SasClientTests.java | 551 ++++++++++++++---- 1 file changed, 424 insertions(+), 127 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 6e6a0f25d112..d190d0b1f6dd 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -42,10 +42,11 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Stream; @@ -1057,6 +1058,228 @@ private static Stream blobSasImplUtilStringToSignSupplier() { + "\nb\n\nencryptionScope\n\n\n\n\n")); } + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") + @ParameterizedTest + @MethodSource("blobSasImplUtilStringToSignUserDelegationKeyRequestHeadersAndParamsSupplier") + public void blobSasImplUtilStringToSignUserDelegationKeyRequestHeadersAndParams(String keyValue, + Map requestHeaders, Map requestQueryParameters, String expectedStringToSign) { + // Arrange + OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + ArrayList stringToSign = new ArrayList<>(); + BlobSasPermission p = new BlobSasPermission().setReadPermission(true); + BlobServiceSasSignatureValues v = new BlobServiceSasSignatureValues(e, p); + UserDelegationKey key = new UserDelegationKey().setValue(keyValue); + String expected; + + //Act + expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); + v.setRequestHeaders(requestHeaders).setRequestQueryParameters(requestQueryParameters); + + BlobSasImplUtil implUtil = new BlobSasImplUtil(v, "containerName", "blobName", null, null, null); + String sasToken = implUtil.generateUserDelegationSas(key, ENVIRONMENT.getPrimaryAccount().getName(), + stringToSign::add, Context.NONE); + + CommonSasQueryParameters token + = BlobUrlParts.parse(cc.getBlobContainerUrl() + "?" + sasToken).getCommonSasQueryParameters(); + + // Assert + assertEqualsForEachLine(stringToSign, expected); + assertEquals(StorageImplUtils.computeHMac256(key.getValue(), expected), token.getSignature()); + } + + private static Stream blobSasImplUtilStringToSignUserDelegationKeyRequestHeadersAndParamsSupplier() { + // Use LinkedHashMap to ensure deterministic iteration order + Map singleHeader = new LinkedHashMap<>(); + singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); + + Map singleQueryParam = new LinkedHashMap<>(); + singleQueryParam.put("comp", "blocklist"); + + Map multipleHeaders = new LinkedHashMap<>(); + multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); + multipleHeaders.put("x-ms-source-if-match", "etag"); + + Map multipleQueryParams = new LinkedHashMap<>(); + multipleQueryParams.put("blockid", "blockidvalue"); + multipleQueryParams.put("comp", "blocklist"); + + return Stream.of( + // Test for no request headers or query parameters + Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue + null, // requestHeaders + null, // requestQueryParameters + "r\n" // permissions + + "\n" // startTime (empty) + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n" // expiryTime + + "/blob/%s/containerName/blobName\n" // canonicalName + + "\n" // keyOid (empty) + + "\n" // keyTid (empty) + + "\n" // keyStart (empty) + + "\n" // keyExpiry (empty) + + "\n" // keyService (empty) + + "\n" // keyVersion (empty) + + "\n" // saoid (empty) + + "\n" // suoid (always empty) + + "\n" // cid (empty) + + "\n" // delegatedUserTenantId (removed - empty) + + "\n" // delegatedUserObjectId (removed - empty) + + "\n" // sasIpRange (empty) + + "\n" // protocol (empty) + + Constants.SAS_SERVICE_VERSION + "\n" // VERSION + + "b\n" // resource + + "\n" // versionSegment (empty) + + "\n" // encryptionScope (empty) + + "\n" // requestHeaders + (empty) no newline appended for empty headers + + "\n" // requestQueryParameters (empty) does not prepend for empty strings + + "\n" // cacheControl (empty) + + "\n" // contentDisposition (empty) + + "\n" // contentEncoding (empty) + + "\n" // contentLanguage (empty) + ), + // Test requestHeaders only (single header) + Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue + singleHeader, // requestHeaders + null, // requestQueryParameters + "r\n" // permissions + + "\n" // startTime (empty) + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n" // expiryTime + + "/blob/%s/containerName/blobName\n" // canonicalName + + "\n" // keyOid (empty) + + "\n" // keyTid (empty) + + "\n" // keyStart (empty) + + "\n" // keyExpiry (empty) + + "\n" // keyService (empty) + + "\n" // keyVersion (empty) + + "\n" // saoid (empty) + + "\n" // suoid (always empty) + + "\n" // cid (empty) + + "\n" // delegatedUserTenantId (removed - empty) + + "\n" // delegatedUserObjectId (removed - empty) + + "\n" // sasIpRange (empty) + + "\n" // protocol (empty) + + Constants.SAS_SERVICE_VERSION + "\n" // VERSION + + "b\n" // resource + + "\n" // versionSegment (empty) + + "\n" // encryptionScope (empty) + + "x-ms-encryption-key-sha256:hashvalue\n\n" // requestHeaders + newline that is added for headers + + "\n" // requestQueryParameters (empty) does not prepend for empty strings + + "\n" // cacheControl (empty) + + "\n" // contentDisposition (empty) + + "\n" // contentEncoding (empty) + + "\n" // contentLanguage (empty) + ), + // Test requestQueryParameters only (single param) + Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue + null, // requestHeaders + singleQueryParam, // requestQueryParameters + "r\n" // permissions + + "\n" // startTime (empty) + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n" // expiryTime + + "/blob/%s/containerName/blobName\n" // canonicalName + + "\n" // keyOid (empty) + + "\n" // keyTid (empty) + + "\n" // keyStart (empty) + + "\n" // keyExpiry (empty) + + "\n" // keyService (empty) + + "\n" // keyVersion (empty) + + "\n" // saoid (empty) + + "\n" // suoid (always empty) + + "\n" // cid (empty) + + "\n" // delegatedUserTenantId (removed - empty) + + "\n" // delegatedUserObjectId (removed - empty) + + "\n" // sasIpRange (empty) + + "\n" // protocol (empty) + + Constants.SAS_SERVICE_VERSION + "\n" // VERSION + + "b\n" // resource + + "\n" // versionSegment (empty) + + "\n" // encryptionScope (empty) + + "\n" // requestHeaders (empty), no newline is appended for empty strings + + "\ncomp:blocklist\n" // requestQueryParameters with prepended newline for query params + + "\n" // cacheControl (empty) + + "\n" // contentDisposition (empty) + + "\n" // contentEncoding (empty) + + "\n" // contentLanguage (empty) + ), + // Test both requestHeaders and requestQueryParameters + Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue + singleHeader, // requestHeaders + singleQueryParam, // requestQueryParameters + "r\n" // permissions + + "\n" // startTime (empty) + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n" // expiryTime + + "/blob/%s/containerName/blobName\n" // canonicalName + + "\n" // keyOid (empty) + + "\n" // keyTid (empty) + + "\n" // keyStart (empty) + + "\n" // keyExpiry (empty) + + "\n" // keyService (empty) + + "\n" // keyVersion (empty) + + "\n" // saoid (empty) + + "\n" // suoid (always empty) + + "\n" // cid (empty) + + "\n" // delegatedUserTenantId (removed - empty) + + "\n" // delegatedUserObjectId (removed - empty) + + "\n" // sasIpRange (empty) + + "\n" // protocol (empty) + + Constants.SAS_SERVICE_VERSION + "\n" // VERSION + + "b\n" // resource + + "\n" // versionSegment (empty) + + "\n" // encryptionScope (empty) + + "x-ms-encryption-key-sha256:hashvalue\n\n" // requestHeaders + + "\ncomp:blocklist\n" // requestQueryParameters + + "\n" // cacheControl (empty) + + "\n" // contentDisposition (empty) + + "\n" // contentEncoding (empty) + + "\n" // contentLanguage (empty) + ), + // Test multiple headers and multiple query parameters + Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue + multipleHeaders, // requestHeaders + multipleQueryParams, // requestQueryParameters + "r\n" // permissions + + "\n" // startTime (empty) + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n" // expiryTime + + "/blob/%s/containerName/blobName\n" // canonicalName + + "\n" // keyOid (empty) + + "\n" // keyTid (empty) + + "\n" // keyStart (empty) + + "\n" // keyExpiry (empty) + + "\n" // keyService (empty) + + "\n" // keyVersion (empty) + + "\n" // saoid (empty) + + "\n" // suoid (always empty) + + "\n" // cid (empty) + + "\n" // delegatedUserTenantId (removed - empty) + + "\n" // delegatedUserObjectId (removed - empty) + + "\n" // sasIpRange (empty) + + "\n" // protocol (empty) + + Constants.SAS_SERVICE_VERSION + "\n" // VERSION + + "b\n" // resource + + "\n" // versionSegment (empty) + + "\n" // encryptionScope (empty) + + "x-ms-encryption-key-sha256:hashvalue\n" + "x-ms-source-if-match:etag\n\n" // + // requestHeaders (multiple, sorted alphabetically) + + "\nblockid:blockidvalue\n" + "comp:blocklist" // requestQueryParameters (multiple, + // sorted alphabetically) + + "\n" // cacheControl (empty) + + "\n" // contentDisposition (empty) + + "\n" // contentEncoding (empty) + + "\n" // contentLanguage (empty) + + "\n" + + )); + } + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest @MethodSource("blobSasImplUtilStringToSignUserDelegationKeySupplier") @@ -1068,6 +1291,7 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); BlobSasPermission p = new BlobSasPermission().setReadPermission(true); BlobServiceSasSignatureValues v = new BlobServiceSasSignatureValues(e, p); + ArrayList stringToSign = new ArrayList<>(); String expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); @@ -1099,11 +1323,12 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim BlobSasImplUtil implUtil = new BlobSasImplUtil(v, "containerName", "blobName", snapId, versionId, encryptionScope); - String sasToken - = implUtil.generateUserDelegationSas(key, ENVIRONMENT.getPrimaryAccount().getName(), Context.NONE); + String sasToken = implUtil.generateUserDelegationSas(key, ENVIRONMENT.getPrimaryAccount().getName(), + stringToSign::add, Context.NONE); CommonSasQueryParameters token = BlobUrlParts.parse(cc.getBlobContainerUrl() + "?" + sasToken).getCommonSasQueryParameters(); + assertEqualsForEachLine(stringToSign, expected); assertEquals(token.getSignature(), StorageImplUtils.computeHMac256(key.getValue(), expected)); } @@ -1111,149 +1336,185 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim We test string to sign functionality directly related toUserDelegation sas specific parameters */ private static Stream blobSasImplUtilStringToSignUserDelegationKeySupplier() { + Map multipleHeaders = new LinkedHashMap<>(); + multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); + multipleHeaders.put("x-ms-source-if-match", "etag"); + + Map multipleQueryParams = new LinkedHashMap<>(); + multipleQueryParams.put("blockid", "blockidvalue"); + multipleQueryParams.put("comp", "blocklist"); + return Stream.of( - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, "2018-06-17", - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", - new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, + // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + // null, null, null, null, + // "r\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, + // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + // null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, + // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + // null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, + // null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, + // null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), + // null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, + // null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, null, null, null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, "2018-06-17", + // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + // null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", + // new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, "snapId", null, null, null, null, null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nbs\nsnapId\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, "control", null, null, null, null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\ncontrol\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, "disposition", null, null, null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\ndisposition\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, "encoding", null, null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\nencoding\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, null, "language", null, null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\nlanguage\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, null, null, "type", null, null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\ntype"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, null, null, null, "versionId", null, null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nbv\nversionId\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, null, null, null, null, "saoid", null, null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, null, null, null, null, null, "cid", null, null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\n"), + // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + // null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, + // "r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\nencryptionScope\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, "snapId", null, null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, "control", null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, "disposition", null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, "encoding", null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, "language", null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, "type", null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, "versionId", null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, "saoid", null, null, null, + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, "cid", null, null, + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n"), + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", "r\n\n" @@ -1348,4 +1609,40 @@ private static Stream accountSasImplUtilStringToSignSupplier() { .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nencryptionScope\n")); } + + private static void assertEqualsForEachLine(ArrayList stringToSign, String expected) { + String actual = stringToSign.get(0); + if (!expected.equals(actual)) { + StringBuilder output = new StringBuilder(); + String[] expectedLines = expected.split("\n", -1); + String[] actualLines = actual.split("\n", -1); + + output.append("\n=== Line-by-Line String-to-Sign Comparison ===\n"); + output.append("Expected lines: ").append(expectedLines.length).append("\n"); + output.append("Actual lines: ").append(actualLines.length).append("\n\n"); + + int maxLines = Math.max(expectedLines.length, actualLines.length); + for (int i = 0; i < maxLines; i++) { + String expLine = i < expectedLines.length ? expectedLines[i] : ""; + String actLine = i < actualLines.length ? actualLines[i] : ""; + + if (!expLine.equals(actLine)) { + output.append("Line ").append(i).append(" differs:\n"); + output.append(" Expected: [").append(expLine).append("]\n"); + output.append(" Actual: [").append(actLine).append("]\n\n"); + } else { + output.append("Line ").append(i).append(" matches: [").append(expLine).append("]\n"); + } + } + + output.append("=== Full Expected String ===\n"); + output.append(expected.replace("\n", "\\n\n")); + output.append("\n\n=== Full Actual String ===\n"); + output.append(actual.replace("\n", "\\n\n")); + + // Print everything at once + System.out.println(output.toString()); + } + assertEquals(expected, actual, "String-to-sign mismatch"); + } } From dd2a7fe11309b038e3e124eff3f635511601ef84 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 28 Jan 2026 12:08:42 -0500 Subject: [PATCH 08/37] uncomment stream of args from blobSasImplUtilStringToSignUserDelegationKeySupplier --- .../azure/storage/blob/SasClientTests.java | 285 +++++++++--------- 1 file changed, 143 insertions(+), 142 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index d190d0b1f6dd..f4cd5a0ab517 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -42,6 +42,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; @@ -1345,148 +1346,148 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup multipleQueryParams.put("comp", "blocklist"); return Stream.of( - // Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - // null, null, null, null, - // "r\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, - // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - // null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, - // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - // null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, - // null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - // null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), - // null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - // null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, null, null, null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, "2018-06-17", - // "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - // null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", - // new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, "snapId", null, null, null, null, null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nbs\nsnapId\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, "control", null, null, null, null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\ncontrol\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, "disposition", null, null, null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\ndisposition\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, "encoding", null, null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\nencoding\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, null, "language", null, null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\nlanguage\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, null, null, "type", null, null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\ntype"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, null, null, null, "versionId", null, null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nbv\nversionId\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, null, null, null, null, "saoid", null, null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, null, null, null, null, null, "cid", null, null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\n"), - // Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - // null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, - // "r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\nencryptionScope\n\n\n\n\n"), + Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, + "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + null, null, null, null, + "r\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, + "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, + "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, + null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, + null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), + null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, + null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, "2018-06-17", + "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, + null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", + new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, "snapId", null, null, null, null, null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbs\nsnapId\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, "control", null, null, null, null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\ncontrol\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, "disposition", null, null, null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\ndisposition\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, "encoding", null, null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\nencoding\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, "language", null, null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\nlanguage\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, "type", null, null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\ntype"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, "versionId", null, null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbv\nversionId\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, "saoid", null, null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, null, "cid", null, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n"), + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\nencryptionScope\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", "r\n\n" From beb0f3df961e64c67eecb487bb333a1fa729164b Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 28 Jan 2026 12:08:57 -0500 Subject: [PATCH 09/37] fix linting issue --- .../java/com/azure/storage/common/implementation/Constants.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java index 3d946dff8461..69fbcd58eae1 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java @@ -364,7 +364,6 @@ public static final class UrlConstants { */ public static final String SAS_ENCRYPTION_SCOPE = "ses"; - /** * The SAS request headers parameter. */ From bb878389b5750f95bf7a6bef8de9f68f0a2e7a15 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 28 Jan 2026 15:05:48 -0500 Subject: [PATCH 10/37] combine test for srh and srq into blobSasImplUtilStringToSignUserDelegationKey --- .../azure/storage/blob/SasClientTests.java | 424 +++++++----------- 1 file changed, 152 insertions(+), 272 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index f4cd5a0ab517..fdc2f0bd3fcb 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -1059,228 +1059,6 @@ private static Stream blobSasImplUtilStringToSignSupplier() { + "\nb\n\nencryptionScope\n\n\n\n\n")); } - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") - @ParameterizedTest - @MethodSource("blobSasImplUtilStringToSignUserDelegationKeyRequestHeadersAndParamsSupplier") - public void blobSasImplUtilStringToSignUserDelegationKeyRequestHeadersAndParams(String keyValue, - Map requestHeaders, Map requestQueryParameters, String expectedStringToSign) { - // Arrange - OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); - ArrayList stringToSign = new ArrayList<>(); - BlobSasPermission p = new BlobSasPermission().setReadPermission(true); - BlobServiceSasSignatureValues v = new BlobServiceSasSignatureValues(e, p); - UserDelegationKey key = new UserDelegationKey().setValue(keyValue); - String expected; - - //Act - expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); - v.setRequestHeaders(requestHeaders).setRequestQueryParameters(requestQueryParameters); - - BlobSasImplUtil implUtil = new BlobSasImplUtil(v, "containerName", "blobName", null, null, null); - String sasToken = implUtil.generateUserDelegationSas(key, ENVIRONMENT.getPrimaryAccount().getName(), - stringToSign::add, Context.NONE); - - CommonSasQueryParameters token - = BlobUrlParts.parse(cc.getBlobContainerUrl() + "?" + sasToken).getCommonSasQueryParameters(); - - // Assert - assertEqualsForEachLine(stringToSign, expected); - assertEquals(StorageImplUtils.computeHMac256(key.getValue(), expected), token.getSignature()); - } - - private static Stream blobSasImplUtilStringToSignUserDelegationKeyRequestHeadersAndParamsSupplier() { - // Use LinkedHashMap to ensure deterministic iteration order - Map singleHeader = new LinkedHashMap<>(); - singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); - - Map singleQueryParam = new LinkedHashMap<>(); - singleQueryParam.put("comp", "blocklist"); - - Map multipleHeaders = new LinkedHashMap<>(); - multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); - multipleHeaders.put("x-ms-source-if-match", "etag"); - - Map multipleQueryParams = new LinkedHashMap<>(); - multipleQueryParams.put("blockid", "blockidvalue"); - multipleQueryParams.put("comp", "blocklist"); - - return Stream.of( - // Test for no request headers or query parameters - Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue - null, // requestHeaders - null, // requestQueryParameters - "r\n" // permissions - + "\n" // startTime (empty) - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" // expiryTime - + "/blob/%s/containerName/blobName\n" // canonicalName - + "\n" // keyOid (empty) - + "\n" // keyTid (empty) - + "\n" // keyStart (empty) - + "\n" // keyExpiry (empty) - + "\n" // keyService (empty) - + "\n" // keyVersion (empty) - + "\n" // saoid (empty) - + "\n" // suoid (always empty) - + "\n" // cid (empty) - + "\n" // delegatedUserTenantId (removed - empty) - + "\n" // delegatedUserObjectId (removed - empty) - + "\n" // sasIpRange (empty) - + "\n" // protocol (empty) - + Constants.SAS_SERVICE_VERSION + "\n" // VERSION - + "b\n" // resource - + "\n" // versionSegment (empty) - + "\n" // encryptionScope (empty) - + "\n" // requestHeaders + (empty) no newline appended for empty headers - + "\n" // requestQueryParameters (empty) does not prepend for empty strings - + "\n" // cacheControl (empty) - + "\n" // contentDisposition (empty) - + "\n" // contentEncoding (empty) - + "\n" // contentLanguage (empty) - ), - // Test requestHeaders only (single header) - Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue - singleHeader, // requestHeaders - null, // requestQueryParameters - "r\n" // permissions - + "\n" // startTime (empty) - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" // expiryTime - + "/blob/%s/containerName/blobName\n" // canonicalName - + "\n" // keyOid (empty) - + "\n" // keyTid (empty) - + "\n" // keyStart (empty) - + "\n" // keyExpiry (empty) - + "\n" // keyService (empty) - + "\n" // keyVersion (empty) - + "\n" // saoid (empty) - + "\n" // suoid (always empty) - + "\n" // cid (empty) - + "\n" // delegatedUserTenantId (removed - empty) - + "\n" // delegatedUserObjectId (removed - empty) - + "\n" // sasIpRange (empty) - + "\n" // protocol (empty) - + Constants.SAS_SERVICE_VERSION + "\n" // VERSION - + "b\n" // resource - + "\n" // versionSegment (empty) - + "\n" // encryptionScope (empty) - + "x-ms-encryption-key-sha256:hashvalue\n\n" // requestHeaders + newline that is added for headers - + "\n" // requestQueryParameters (empty) does not prepend for empty strings - + "\n" // cacheControl (empty) - + "\n" // contentDisposition (empty) - + "\n" // contentEncoding (empty) - + "\n" // contentLanguage (empty) - ), - // Test requestQueryParameters only (single param) - Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue - null, // requestHeaders - singleQueryParam, // requestQueryParameters - "r\n" // permissions - + "\n" // startTime (empty) - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" // expiryTime - + "/blob/%s/containerName/blobName\n" // canonicalName - + "\n" // keyOid (empty) - + "\n" // keyTid (empty) - + "\n" // keyStart (empty) - + "\n" // keyExpiry (empty) - + "\n" // keyService (empty) - + "\n" // keyVersion (empty) - + "\n" // saoid (empty) - + "\n" // suoid (always empty) - + "\n" // cid (empty) - + "\n" // delegatedUserTenantId (removed - empty) - + "\n" // delegatedUserObjectId (removed - empty) - + "\n" // sasIpRange (empty) - + "\n" // protocol (empty) - + Constants.SAS_SERVICE_VERSION + "\n" // VERSION - + "b\n" // resource - + "\n" // versionSegment (empty) - + "\n" // encryptionScope (empty) - + "\n" // requestHeaders (empty), no newline is appended for empty strings - + "\ncomp:blocklist\n" // requestQueryParameters with prepended newline for query params - + "\n" // cacheControl (empty) - + "\n" // contentDisposition (empty) - + "\n" // contentEncoding (empty) - + "\n" // contentLanguage (empty) - ), - // Test both requestHeaders and requestQueryParameters - Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue - singleHeader, // requestHeaders - singleQueryParam, // requestQueryParameters - "r\n" // permissions - + "\n" // startTime (empty) - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" // expiryTime - + "/blob/%s/containerName/blobName\n" // canonicalName - + "\n" // keyOid (empty) - + "\n" // keyTid (empty) - + "\n" // keyStart (empty) - + "\n" // keyExpiry (empty) - + "\n" // keyService (empty) - + "\n" // keyVersion (empty) - + "\n" // saoid (empty) - + "\n" // suoid (always empty) - + "\n" // cid (empty) - + "\n" // delegatedUserTenantId (removed - empty) - + "\n" // delegatedUserObjectId (removed - empty) - + "\n" // sasIpRange (empty) - + "\n" // protocol (empty) - + Constants.SAS_SERVICE_VERSION + "\n" // VERSION - + "b\n" // resource - + "\n" // versionSegment (empty) - + "\n" // encryptionScope (empty) - + "x-ms-encryption-key-sha256:hashvalue\n\n" // requestHeaders - + "\ncomp:blocklist\n" // requestQueryParameters - + "\n" // cacheControl (empty) - + "\n" // contentDisposition (empty) - + "\n" // contentEncoding (empty) - + "\n" // contentLanguage (empty) - ), - // Test multiple headers and multiple query parameters - Arguments.of("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue - multipleHeaders, // requestHeaders - multipleQueryParams, // requestQueryParameters - "r\n" // permissions - + "\n" // startTime (empty) - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" // expiryTime - + "/blob/%s/containerName/blobName\n" // canonicalName - + "\n" // keyOid (empty) - + "\n" // keyTid (empty) - + "\n" // keyStart (empty) - + "\n" // keyExpiry (empty) - + "\n" // keyService (empty) - + "\n" // keyVersion (empty) - + "\n" // saoid (empty) - + "\n" // suoid (always empty) - + "\n" // cid (empty) - + "\n" // delegatedUserTenantId (removed - empty) - + "\n" // delegatedUserObjectId (removed - empty) - + "\n" // sasIpRange (empty) - + "\n" // protocol (empty) - + Constants.SAS_SERVICE_VERSION + "\n" // VERSION - + "b\n" // resource - + "\n" // versionSegment (empty) - + "\n" // encryptionScope (empty) - + "x-ms-encryption-key-sha256:hashvalue\n" + "x-ms-source-if-match:etag\n\n" // - // requestHeaders (multiple, sorted alphabetically) - + "\nblockid:blockidvalue\n" + "comp:blocklist" // requestQueryParameters (multiple, - // sorted alphabetically) - + "\n" // cacheControl (empty) - + "\n" // contentDisposition (empty) - + "\n" // contentEncoding (empty) - + "\n" // contentLanguage (empty) - + "\n" - - )); - } - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest @MethodSource("blobSasImplUtilStringToSignUserDelegationKeySupplier") @@ -1288,7 +1066,8 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim OffsetDateTime keyStart, OffsetDateTime keyExpiry, String keyService, String keyVersion, String keyValue, SasIpRange ipRange, SasProtocol protocol, String snapId, String cacheControl, String disposition, String encoding, String language, String type, String versionId, String saoid, String cid, - String encryptionScope, String delegatedUserObjectId, String expectedStringToSign) { + String encryptionScope, String delegatedUserObjectId, Map requestHeaders, + Map requestQueryParameters, String expectedStringToSign) { OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); BlobSasPermission p = new BlobSasPermission().setReadPermission(true); BlobServiceSasSignatureValues v = new BlobServiceSasSignatureValues(e, p); @@ -1312,7 +1091,9 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim .setContentType(type) .setPreauthorizedAgentObjectId(saoid) .setCorrelationId(cid) - .setDelegatedUserObjectId(delegatedUserObjectId); + .setDelegatedUserObjectId(delegatedUserObjectId) + .setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParameters); UserDelegationKey key = new UserDelegationKey().setSignedObjectId(keyOid) .setSignedTenantId(keyTid) @@ -1337,6 +1118,13 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim We test string to sign functionality directly related toUserDelegation sas specific parameters */ private static Stream blobSasImplUtilStringToSignUserDelegationKeySupplier() { + // Use LinkedHashMap to ensure deterministic iteration order + Map singleHeader = new LinkedHashMap<>(); + singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); + + Map singleQueryParam = new LinkedHashMap<>(); + singleQueryParam.put("comp", "blocklist"); + Map multipleHeaders = new LinkedHashMap<>(); multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); multipleHeaders.put("x-ms-source-if-match", "etag"); @@ -1348,7 +1136,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup return Stream.of( Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, + null, null, null, null, null, null, "r\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) @@ -1356,173 +1144,265 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, + null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, + null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, + null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, + null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, "2018-06-17", "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, + null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", - new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, + new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, + SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, "snapId", null, null, null, null, null, null, null, null, null, null, + null, "snapId", null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n"), + + "\nbs\nsnapId\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, "control", null, null, null, null, null, null, null, null, null, + null, null, "control", null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n"), + + "\nb\n\n\n\n\ncontrol\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, "disposition", null, null, null, null, null, null, null, null, + null, null, null, "disposition", null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n"), + + "\nb\n\n\n\n\n\ndisposition\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, "encoding", null, null, null, null, null, null, null, + null, null, null, null, "encoding", null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n"), + + "\nb\n\n\n\n\n\n\nencoding\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, "language", null, null, null, null, null, null, + null, null, null, null, null, "language", null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n"), + + "\nb\n\n\n\n\n\n\n\nlanguage\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, "type", null, null, null, null, null, + null, null, null, null, null, null, "type", null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype"), + + "\nb\n\n\n\n\n\n\n\n\ntype"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, "versionId", null, null, null, null, + null, null, null, null, null, null, null, "versionId", null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n"), + + "\nbv\nversionId\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, "saoid", null, null, null, + null, null, null, null, null, null, null, null, "saoid", null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, "cid", null, null, + null, null, null, null, null, null, null, null, null, "cid", null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, + null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n"), + + "\nb\n\nencryptionScope\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", + null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n")); + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Test requestHeaders only (single header) + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, null, null, null, null, singleHeader, null, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n"), + // Test requestQueryParameters only (single param) + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, null, null, null, null, null, singleQueryParam, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n"), + // Test both requestHeaders and requestQueryParameters + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, null, null, null, null, singleHeader, singleQueryParam, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n"), + // Test multiple headers and multiple query parameters + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, null, null, null, null, null, null, null, multipleHeaders, + multipleQueryParams, + "r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" + + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n"), + // Test with all parameters populated + Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), // startTime + "11111111-1111-1111-1111-111111111111", // keyOid + "22222222-2222-2222-2222-222222222222", // keyTid + OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), // keyStart + OffsetDateTime.of(LocalDateTime.of(2018, 6, 1, 0, 0), ZoneOffset.UTC), // keyExpiry + "b", // keyService + "2018-06-17", // keyVersion + "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue + new SasIpRange(), // ipRange + SasProtocol.HTTPS_ONLY, // protocol + "snapId", // snapId + "control", // cacheControl + "disposition", // contentDisposition + "encoding", // contentEncoding + "language", // contentLanguage + "type", // contentType + null, // versionId, versionId and snapId are mutually exclusive + "saoid", // saoid (preauthorizedAgentObjectId) + "cid", // cid (correlationId) + "encryptionScope", // encryptionScope + "delegatedOid", // delegatedUserObjectId + multipleHeaders, // requestHeaders + multipleQueryParams, // requestQueryParameters + "r\n" // permissions + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) // startTime + + "\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) // expiryTime + + "\n/blob/%s/containerName/blobName\n" // canonicalName + + "11111111-1111-1111-1111-111111111111\n" // keyOid + + "22222222-2222-2222-2222-222222222222\n" // keyTid + + "2018-01-01T00:00:00Z\n" // keyStart + + "2018-06-01T00:00:00Z\n" // keyExpiry + + "b\n" // keyService + + "2018-06-17\n" // keyVersion + + "saoid\n" // saoid (preauthorizedAgentObjectId) + + "\n" // suoid (always empty) + + "cid\n" // cid (correlationId) + + "\n" // delegatedUserTenantId (removed - empty) + + "delegatedOid\n" // delegatedUserObjectId + + "ip\n" // sasIpRange + + SasProtocol.HTTPS_ONLY + "\n" // protocol + + Constants.SAS_SERVICE_VERSION + "\n" // VERSION + + "bs\n" // resource (blob snapshot) + + "snapId\n" // snapId (versionSegment with snapId) + + "encryptionScope\n" // encryptionScope + + "x-ms-encryption-key-sha256:hashvalue\n" // requestHeaders (multiple) + + "x-ms-source-if-match:etag\n\n" // requestHeaders continuation + newline separator + + "\nblockid:blockidvalue\n" // requestQueryParameters (multiple, with prepended newline) + + "comp:blocklist\n" // requestQueryParameters continuation + + "control\n" // cacheControl + + "disposition\n" // contentDisposition + + "encoding\n" // contentEncoding + + "language\n" // contentLanguage + + "type" // contentType (no trailing newline) + )); } @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") From 42ad7c568cf74623c7b2ea4f136e6e2baa7aea3b Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 28 Jan 2026 16:50:53 -0500 Subject: [PATCH 11/37] add recordings for blobSasImplUtilStringToSignUserDelegationKey --- sdk/storage/azure-storage-blob/assets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index a2bc9bdaa663..f9a5c195881a 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_f26563826e" + "Tag": "java/storage/azure-storage-blob_6631ad464e" } From d54b8c21de847047079ecb8fa5d1f06271f457a5 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 28 Jan 2026 17:02:05 -0500 Subject: [PATCH 12/37] add additional srh test to check for trailing newline --- .../common/implementation/SasImplUtilsTests.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index 108bb8f31408..f222430e3904 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -8,7 +8,8 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.assertEquals;; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals;; public class SasImplUtilsTests { @@ -29,6 +30,15 @@ public void formatRequestHeadersForSasSigningEmptyReturnsEmptyString() { assertEquals("", SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders)); } + @Test + public void formatRequestHeadersForSasSigningReturnsWithLastCharAsNewline() { + requestHeaders.put("Some-Header", "someValue"); + String headerString = SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders); + + assertNotEquals("", headerString); + assertEquals("\n", headerString.substring(headerString.length() - 1)); + } + @Test public void formatRequestHeadersForSasSigningPopulatedHeaders() { requestHeaders.put(Constants.HeaderConstants.ENCRYPTION_KEY, "encryptionKeyValue"); From 4e8a5391d4e90e7796049201ae67cfdeb1c59812 Mon Sep 17 00:00:00 2001 From: browndav Date: Wed, 28 Jan 2026 17:32:23 -0500 Subject: [PATCH 13/37] add tests for srq --- .../implementation/SasImplUtilsTests.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index f222430e3904..d5b39c284562 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -14,10 +14,12 @@ public class SasImplUtilsTests { private Map requestHeaders; + private Map requestQueryParams; @BeforeEach public void setup() { requestHeaders = new HashMap<>(); + requestQueryParams = new HashMap<>(); } @Test @@ -60,4 +62,43 @@ public void formatRequestHeadersForSasSigningPopulatedHeaders() { assertEquals(4, newLineCount); assertEquals(sortedExpected, sortedHeaders); } + + @Test + public void formatRequestQueryParamsForSasSigningNullReturnsEmptyString() { + assertEquals("", SasImplUtils.formatRequestQueryParametersForSasSigning(null)); + } + + @Test + public void formatRequestQueryParamsForSasSigningEmptyReturnsEmptyString() { + assertEquals("", SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams)); + } + + @Test + public void formatRequestQueryParamsForSasSigningReturnsWithFirstCharAsNewline() { + requestQueryParams.put("someParam", "someValue"); + + String queryParamString = SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams); + + assertNotEquals("", queryParamString); + assertEquals("\n", queryParamString.substring(0, 1)); + } + + @Test + public void formatRequestQueryParamsForSasSigningPopulatedParams() { + requestQueryParams.put("paramA", "valueA"); + requestQueryParams.put("paramB", "valueB"); + requestQueryParams.put("paramC", "valueC"); + String expected = "\nparamA:valueA\nparamB:valueB\nparamC:valueC"; + + String queryParams = SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams); + Integer newLineCount + = Arrays.stream(queryParams.split("")).filter(s -> s.equals("\n")).collect(Collectors.toList()).size(); + String sortedExpected + = "\n" + Arrays.stream(expected.substring(1).split("\n")).sorted().collect(Collectors.joining("\n")); + String sortedQueryParams + = "\n" + Arrays.stream(queryParams.substring(1).split("\n")).sorted().collect(Collectors.joining("\n")); + + assertEquals(3, newLineCount); + assertEquals(sortedExpected, sortedQueryParams); + } } From 85593646748ce26d60f81c9d172a0d0eb24c5ca7 Mon Sep 17 00:00:00 2001 From: browndav Date: Thu, 29 Jan 2026 17:02:31 -0500 Subject: [PATCH 14/37] add tests for srq and srh to datalake --- .../azure/storage/file/datalake/SasTests.java | 157 ++++++++++++------ 1 file changed, 109 insertions(+), 48 deletions(-) diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 9e6979070c7c..07f50bb64cda 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -41,8 +41,11 @@ import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.stream.Stream; import static com.azure.storage.common.test.shared.StorageCommonTestUtils.getOidFromToken; @@ -839,10 +842,12 @@ private static Stream sasImplUtilStringToSignSupplier() { public void sasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, String keyOid, String keyTid, OffsetDateTime keyStart, OffsetDateTime keyExpiry, String keyService, String keyVersion, String keyValue, SasIpRange ipRange, SasProtocol protocol, String cacheControl, String disposition, String encoding, - String language, String type, String saoid, String suoid, String cid, String expectedStringToSign) { + String language, String type, Map requestHeaders, Map requestQueryParameters, + String saoid, String suoid, String cid, String expectedStringToSign) { OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); PathSasPermission p = new PathSasPermission().setReadPermission(true); + ArrayList stringToSign = new ArrayList<>(); String expected = String.format(expectedStringToSign, ENVIRONMENT.getDataLakeAccount().getName()); DataLakeServiceSasSignatureValues v = new DataLakeServiceSasSignatureValues(e, p).setPermissions(p) @@ -856,7 +861,9 @@ public void sasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, S .setContentType(type) .setCorrelationId(cid) .setPreauthorizedAgentObjectId(saoid) - .setAgentObjectId(suoid); + .setAgentObjectId(suoid) + .setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParameters); if (ipRange != null) { v.setSasIpRange(new SasIpRange().setIpMin("ip")); @@ -872,25 +879,43 @@ public void sasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, S DataLakeSasImplUtil util = new DataLakeSasImplUtil(v, "fileSystemName", "pathName", false); util.ensureState(); + String sasToken = util.generateUserDelegationSas(key, ENVIRONMENT.getDataLakeAccount().getName(), + stringToSign::add, Context.NONE); + assertEqualsForEachLine(stringToSign, expected); assertEquals(expected, util.stringToSign(key, util.getCanonicalName(ENVIRONMENT.getDataLakeAccount().getName()))); } private static Stream sasImplUtilStringToSignUserDelegationKeySupplier() { + // Use LinkedHashMap to ensure deterministic iteration order + Map singleHeader = new LinkedHashMap<>(); + singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); + + Map singleQueryParam = new LinkedHashMap<>(); + singleQueryParam.put("comp", "blocklist"); + + Map multipleHeaders = new LinkedHashMap<>(); + multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); + multipleHeaders.put("x-ms-source-if-match", "etag"); + + Map multipleQueryParams = new LinkedHashMap<>(); + multipleQueryParams.put("blockid", "blockidvalue"); + multipleQueryParams.put("comp", "blocklist"); + // We test string to sign functionality directly related to user delegation sas specific parameters return Stream.of( - // startTime | keyOid | keyTid | keyStart | keyExpiry | keyService | keyVersion | keyValue | ipRange | protocol | cacheControl | disposition | encoding | language | type | saoid | suoid | cid | expectedStringToSign + // startTime | keyOid | keyTid | keyStart | keyExpiry | keyService | keyVersion | keyValue | ipRange | protocol | cacheControl | disposition | encoding | language | type | requestHeaders | requestQueryParameters | saoid | suoid | cid | expectedStringToSign Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, + null, null, null, "r\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) @@ -898,124 +923,129 @@ private static Stream sasImplUtilStringToSignUserDelegationKeySupplie + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, + null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, + null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, + null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, + null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, "2018-06-17", "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, + null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", - new SasIpRange(), null, null, null, null, null, null, null, null, null, + new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, + null, null, null, "encoding", null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, "control", null, null, null, null, null, null, null, + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\nencoding\n\n"), + Arguments.of(null, null, null, null, null, null, null, null, "type", null, null, null, null, null, null, + null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n"), + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\ntype"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, "disposition", null, null, null, null, null, null, + null, null, null, null, null, null, null, null, "saoid", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n"), + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, "encoding", null, null, null, null, null, + null, null, null, null, null, null, null, null, null, "suoid", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n"), + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\nsuoid\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, "language", null, null, null, null, + null, null, null, null, null, null, null, null, null, null, "cid", "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n"), + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Test requestHeaders only (single header) Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, "type", null, null, null, + null, null, null, null, null, null, singleHeader, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype"), + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n"), + // Test requestQueryParameters only (single param) Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, "saoid", null, null, + null, null, null, null, null, null, null, singleQueryParam, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n"), + // Test both requestHeaders and requestQueryParameters Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, "suoid", null, + null, null, null, null, null, null, singleHeader, singleQueryParam, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\nsuoid\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n"), + // Test multiple headers and multiple query parameters Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, "cid", + null, null, null, null, null, null, multipleHeaders, multipleQueryParams, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n")); + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" + + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n")); } @Test @@ -1085,4 +1115,35 @@ public void canUseSasToAuthenticate() { .getProperties()); } + private static void assertEqualsForEachLine(ArrayList stringToSign, String expected) { + String actual = stringToSign.get(0); + if (!expected.equals(actual)) { + StringBuilder output = new StringBuilder(); + String[] expectedLines = expected.split("\n", -1); + String[] actualLines = actual.split("\n", -1); + + output.append("\n=== Line-by-Line String-to-Sign Comparison ===\n"); + output.append("Expected lines: ").append(expectedLines.length).append("\n"); + output.append("Actual lines: ").append(actualLines.length).append("\n\n"); + + int maxLines = Math.max(expectedLines.length, actualLines.length); + for (int i = 0; i < maxLines; i++) { + String expLine = i < expectedLines.length ? expectedLines[i] : ""; + String actLine = i < actualLines.length ? actualLines[i] : ""; + + if (!expLine.equals(actLine)) { + output.append("Line ").append(i).append(" differs:\n"); + output.append(" Expected: [").append(expLine).append("]\n"); + output.append(" Actual: [").append(actLine).append("]\n\n"); + } else { + output.append("Line ").append(i).append(" matches: [").append(expLine).append("]\n"); + } + } + + // Print everything at once + System.out.println(output.toString()); + } + assertEquals(expected, actual, "String-to-sign mismatch"); + } + } From 88a793ae1d343de375c1df55f8c3bb9255974c65 Mon Sep 17 00:00:00 2001 From: browndav Date: Thu, 29 Jan 2026 17:50:56 -0500 Subject: [PATCH 15/37] fix failing datalake sas tests --- .../java/com/azure/storage/file/datalake/SasTests.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 07f50bb64cda..6296694b5afd 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -985,12 +985,12 @@ private static Stream sasImplUtilStringToSignUserDelegationKeySupplie .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\nencoding\n\n"), - Arguments.of(null, null, null, null, null, null, null, null, "type", null, null, null, null, null, null, - null, + Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, + null, null, null, null, null, "type", null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\ntype"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, "saoid", null, null, @@ -1000,7 +1000,7 @@ private static Stream sasImplUtilStringToSignUserDelegationKeySupplie + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, "suoid", null, null, + null, null, null, null, null, null, null, null, null, "suoid", null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) From 47ef9c7aa7a890cfee3cf3cf93fae8e2fda31672 Mon Sep 17 00:00:00 2001 From: browndav Date: Thu, 29 Jan 2026 17:54:41 -0500 Subject: [PATCH 16/37] add recordings for blobSasImplUtilStringToSignUserDelegationKey --- sdk/storage/azure-storage-file-datalake/assets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-file-datalake/assets.json b/sdk/storage/azure-storage-file-datalake/assets.json index 90e1f30a59e7..f5bb8d4f9891 100644 --- a/sdk/storage/azure-storage-file-datalake/assets.json +++ b/sdk/storage/azure-storage-file-datalake/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-file-datalake", - "Tag": "java/storage/azure-storage-file-datalake_e7c65c4771" + "Tag": "java/storage/azure-storage-file-datalake_cc5d8d21d2" } From e06736ea7fbe96d3580a112651aa8e3599df8568 Mon Sep 17 00:00:00 2001 From: browndav Date: Fri, 30 Jan 2026 13:59:07 -0500 Subject: [PATCH 17/37] refactor SasTests to make the suppliers easier to read and write --- .../common/test/shared/SasTestData.java | 79 +++++ .../shared/UserDelegationSasTestData.java | 184 ++++++++++++ .../azure/storage/file/datalake/SasTests.java | 273 +++++++++--------- 3 files changed, 397 insertions(+), 139 deletions(-) create mode 100644 sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java create mode 100644 sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java new file mode 100644 index 000000000000..5fa488b87848 --- /dev/null +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.storage.common.test.shared; +import com.azure.storage.common.sas.SasIpRange; +import com.azure.storage.common.sas.SasProtocol; +import org.junit.jupiter.params.provider.Arguments; +import java.time.OffsetDateTime; +/** + * Helper class to build test arguments for regular SAS string-to-sign tests. + * This is the base class that contains common fields shared by both regular SAS and user delegation SAS. + * All fields default to null, so you only need to set the ones you're testing. + *

+ * For user delegation SAS tests, use {@link UserDelegationSasTestData} which extends this class. + */ +public class SasTestData { + // Common fields for all SAS types + protected OffsetDateTime startTime; + protected SasIpRange ipRange; + protected SasProtocol protocol; + protected String cacheControl; + protected String disposition; + protected String encoding; + protected String language; + protected String type; + protected String expectedStringToSign; + // Regular SAS specific field + protected String identifier; // Signed identifier for regular SAS + public SasTestData setStartTime(OffsetDateTime startTime) { + this.startTime = startTime; + return this; + } + public SasTestData setIdentifier(String identifier) { + this.identifier = identifier; + return this; + } + public SasTestData setIpRange(SasIpRange ipRange) { + this.ipRange = ipRange; + return this; + } + public SasTestData setProtocol(SasProtocol protocol) { + this.protocol = protocol; + return this; + } + public SasTestData setCacheControl(String cacheControl) { + this.cacheControl = cacheControl; + return this; + } + public SasTestData setDisposition(String disposition) { + this.disposition = disposition; + return this; + } + public SasTestData setEncoding(String encoding) { + this.encoding = encoding; + return this; + } + public SasTestData setLanguage(String language) { + this.language = language; + return this; + } + public SasTestData setType(String type) { + this.type = type; + return this; + } + public SasTestData setExpectedStringToSign(String expectedStringToSign) { + this.expectedStringToSign = expectedStringToSign; + return this; + } + /** + * Converts to Arguments for regular SAS tests. + * Returns arguments in this order: + * startTime, identifier, ipRange, protocol, cacheControl, disposition, encoding, language, type, expectedStringToSign + * + * @return Arguments for parameterized tests matching the signature of regular SAS test methods + */ + public Arguments toArguments() { + return Arguments.of(startTime, identifier, ipRange, protocol, cacheControl, disposition, encoding, language, + type, expectedStringToSign); + } +} diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java new file mode 100644 index 000000000000..c90554e1627b --- /dev/null +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java @@ -0,0 +1,184 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.storage.common.test.shared; + +import com.azure.storage.common.sas.SasIpRange; +import com.azure.storage.common.sas.SasProtocol; +import org.junit.jupiter.params.provider.Arguments; + +import java.time.OffsetDateTime; +import java.util.Map; + +/** + * Helper class to build test arguments for User Delegation SAS string-to-sign tests. + * Extends {@link SasTestData} to inherit common SAS fields. + * All fields default to null, so you only need to set the ones you're testing. + *

+ * Note: User delegation SAS does NOT use the 'identifier' field (that's for regular SAS). + * Request headers and query parameters are only used in user delegation SAS. + *

+ * For regular SAS tests, use {@link SasTestData} directly. + */ +public class UserDelegationSasTestData extends SasTestData { + // User delegation SAS specific fields + private String keyOid; + private String keyTid; + private OffsetDateTime keyStart; + private OffsetDateTime keyExpiry; + private String keyService; + private String keyVersion; + private String keyValue; + private Map requestHeaders; + private Map requestQueryParameters; + private String saoid; + private String suoid; + private String cid; + + // Override parent setters to return UserDelegationSasTestData for fluent API + @Override + public UserDelegationSasTestData setStartTime(OffsetDateTime startTime) { + super.setStartTime(startTime); + return this; + } + + @Override + public UserDelegationSasTestData setIpRange(SasIpRange ipRange) { + super.setIpRange(ipRange); + return this; + } + + @Override + public UserDelegationSasTestData setProtocol(SasProtocol protocol) { + super.setProtocol(protocol); + return this; + } + + @Override + public UserDelegationSasTestData setCacheControl(String cacheControl) { + super.setCacheControl(cacheControl); + return this; + } + + @Override + public UserDelegationSasTestData setDisposition(String disposition) { + super.setDisposition(disposition); + return this; + } + + @Override + public UserDelegationSasTestData setEncoding(String encoding) { + super.setEncoding(encoding); + return this; + } + + @Override + public UserDelegationSasTestData setLanguage(String language) { + super.setLanguage(language); + return this; + } + + @Override + public UserDelegationSasTestData setType(String type) { + super.setType(type); + return this; + } + + @Override + public UserDelegationSasTestData setExpectedStringToSign(String expectedStringToSign) { + super.setExpectedStringToSign(expectedStringToSign); + return this; + } + + // User delegation SAS specific setters + + public UserDelegationSasTestData setKeyOid(String keyOid) { + this.keyOid = keyOid; + return this; + } + + public UserDelegationSasTestData setKeyTid(String keyTid) { + this.keyTid = keyTid; + return this; + } + + public UserDelegationSasTestData setKeyStart(OffsetDateTime keyStart) { + this.keyStart = keyStart; + return this; + } + + public UserDelegationSasTestData setKeyExpiry(OffsetDateTime keyExpiry) { + this.keyExpiry = keyExpiry; + return this; + } + + public UserDelegationSasTestData setKeyService(String keyService) { + this.keyService = keyService; + return this; + } + + public UserDelegationSasTestData setKeyVersion(String keyVersion) { + this.keyVersion = keyVersion; + return this; + } + + public UserDelegationSasTestData setKeyValue(String keyValue) { + this.keyValue = keyValue; + return this; + } + + public UserDelegationSasTestData setRequestHeaders(Map requestHeaders) { + this.requestHeaders = requestHeaders; + return this; + } + + public UserDelegationSasTestData setRequestQueryParameters(Map requestQueryParameters) { + this.requestQueryParameters = requestQueryParameters; + return this; + } + + public UserDelegationSasTestData setSaoid(String saoid) { + this.saoid = saoid; + return this; + } + + public UserDelegationSasTestData setSuoid(String suoid) { + this.suoid = suoid; + return this; + } + + public UserDelegationSasTestData setCid(String cid) { + this.cid = cid; + return this; + } + + /** + * Converts to Arguments for user delegation SAS tests. + * Returns arguments with or without request headers/query parameters based on the parameter. + * + * @param withHeadersAndParams Whether to include request headers and query parameters in the test data. + * @return Arguments for parameterized tests matching the signature of user delegation SAS test methods + */ + public Arguments toArguments(boolean withHeadersAndParams) { + if (withHeadersAndParams) { + return Arguments.of(startTime, keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, + ipRange, protocol, cacheControl, disposition, encoding, language, type, requestHeaders, + requestQueryParameters, saoid, suoid, cid, expectedStringToSign); + } else { + return Arguments.of(startTime, keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, + ipRange, protocol, cacheControl, disposition, encoding, language, type, saoid, suoid, cid, expectedStringToSign); + } + } + + /** + * Converts to Arguments for user delegation SAS tests with request headers and query parameters. + * This is a convenience method that calls {@link #toArguments(boolean)} with true. + * + * @return Arguments for parameterized tests with headers and query parameters included + */ + public Arguments toArguments() { + return toArguments(true); + } +} + + diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 6296694b5afd..8984681b6388 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -14,6 +14,8 @@ import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; import com.azure.storage.common.test.shared.StorageCommonTestUtils; +import com.azure.storage.common.test.shared.SasTestData; +import com.azure.storage.common.test.shared.UserDelegationSasTestData; import com.azure.storage.common.test.shared.extensions.LiveOnly; import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion; import com.azure.storage.file.datalake.implementation.util.DataLakeSasImplUtil; @@ -778,62 +780,45 @@ private static Stream sasImplUtilStringToSignSupplier() { // /blob/accountName. We test canonicalization of resources later. Again, this is not to test a fully functional // sas but the construction of the string to sign. // Signed resource is tested elsewhere, as we work some minor magic in choosing which value to use. - return Stream.of( - // startTime | identifier | ipRange | protocol | cacheControl | disposition | encoding | language | type | expectedStringToSign - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - null, null, - "r\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, "id", null, null, null, null, null, null, null, "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, new SasIpRange(), null, null, null, null, null, null, "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, SasProtocol.HTTPS_ONLY, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, "control", null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n"), - Arguments.of(null, null, null, null, null, "disposition", null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n"), - Arguments.of(null, null, null, null, null, null, "encoding", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n"), - Arguments.of(null, null, null, null, null, null, null, "language", null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n"), - Arguments.of(null, null, null, null, null, null, null, null, "type", - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype")); + OffsetDateTime expiryTime = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + String expiryTimeStr = Constants.ISO_8601_UTC_DATE_FORMATTER.format(expiryTime); + + return Stream.of(new SasTestData().setStartTime(expiryTime) + .setExpectedStringToSign("r\n" + expiryTimeStr + "\n" + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toArguments(), + new SasTestData().setIdentifier("id") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\nid\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toArguments(), + new SasTestData().setIpRange(new SasIpRange()) + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\nip\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toArguments(), + new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n" + + SasProtocol.HTTPS_ONLY + "\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toArguments(), + new SasTestData().setCacheControl("control") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\ncontrol\n\n\n\n") + .toArguments(), + new SasTestData().setDisposition("disposition") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\ndisposition\n\n\n") + .toArguments(), + new SasTestData().setEncoding("encoding") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\nencoding\n\n") + .toArguments(), + new SasTestData().setLanguage("language") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\nlanguage\n") + .toArguments(), + new SasTestData().setType("type") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\ntype") + .toArguments()); } @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2020-12-06") @@ -905,147 +890,157 @@ private static Stream sasImplUtilStringToSignUserDelegationKeySupplie // We test string to sign functionality directly related to user delegation sas specific parameters return Stream.of( - // startTime | keyOid | keyTid | keyStart | keyExpiry | keyService | keyVersion | keyValue | ipRange | protocol | cacheControl | disposition | encoding | language | type | requestHeaders | requestQueryParameters | saoid | suoid | cid | expectedStringToSign - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, - "r\n" + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, - "r\n\n" + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyOid("11111111-1111-1111-1111-111111111111") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyTid("22222222-2222-2222-2222-222222222222") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData() + .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData() + .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyService("b") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, "2018-06-17", - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, - "r\n\n" + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyVersion("2018-06-17") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", - new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setIpRange(new SasIpRange()) + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, "encoding", null, null, null, null, null, null, null, - "r\n\n" + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setEncoding("encoding") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\nencoding\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, "type", null, null, null, null, null, - "r\n\n" + + "\nb\n\n\n\n\n\n\nencoding\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setType("type") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\ntype"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, "saoid", null, null, - "r\n\n" + + "\nb\n\n\n\n\n\n\n\n\ntype") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setSaoid("saoid") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, "suoid", null, - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setSuoid("suoid") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\nsuoid\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, "cid", - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setCid("cid") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - // Test requestHeaders only (single header) - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, singleHeader, null, null, null, null, - "r\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestHeaders(singleHeader) + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n"), - // Test requestQueryParameters only (single param) - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, singleQueryParam, null, null, null, - "r\n\n" + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestQueryParameters(singleQueryParam) + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n"), - // Test both requestHeaders and requestQueryParameters - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, singleHeader, singleQueryParam, null, null, null, - "r\n\n" + + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestHeaders(singleHeader) + .setRequestQueryParameters(singleQueryParam) + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n"), - // Test multiple headers and multiple query parameters - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, multipleHeaders, multipleQueryParams, null, null, null, - "r\n\n" + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n") + .toArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestHeaders(multipleHeaders) + .setRequestQueryParameters(multipleQueryParams) + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" - + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n")); + + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n") + .toArguments()); } @Test From 7c8b6175e74bd0e66ebef247ab10b74789402377 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 09:40:45 -0800 Subject: [PATCH 18/37] making new values in commonsasqueryparameters final --- .../azure/storage/common/sas/CommonSasQueryParameters.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java index b1e5f103e4e5..c79a1f5b9e54 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java @@ -49,8 +49,8 @@ public class CommonSasQueryParameters { private final String correlationId; private final String encryptionScope; private final String delegatedUserObjectId; - private Map requestHeaders; - private Map requestQueryParameters; + private final Map requestHeaders; + private final Map requestQueryParameters; /** * Creates a new {@link CommonSasQueryParameters} object. From 5676ff37e380b9d61f4a6242059dd7714f756097 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 09:44:11 -0800 Subject: [PATCH 19/37] adding note to new sas query param javadocs that they're only for UD sas --- .../storage/blob/sas/BlobServiceSasSignatureValues.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java index e57ce60a1303..7e2aee2f3296 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/sas/BlobServiceSasSignatureValues.java @@ -607,6 +607,8 @@ public BlobServiceSasSignatureValues setDelegatedUserObjectId(String delegatedUs * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. * Any usage of the SAS must include these headers and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @return The custom request headers to be set when the SAS is used. */ public Map getRequestHeaders() { @@ -617,6 +619,8 @@ public Map getRequestHeaders() { * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. * Any usage of the SAS must include these headers and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @param requestHeaders The custom request headers to be set when the SAS is used. * @return the updated BlobServiceSasSignatureValues object */ @@ -629,6 +633,8 @@ public BlobServiceSasSignatureValues setRequestHeaders(Map reque * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in * the SAS. Any usage of the SAS must include these query parameters and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @return The custom query parameters to be set when the SAS is used. */ public Map getRequestQueryParameters() { @@ -639,6 +645,8 @@ public Map getRequestQueryParameters() { * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in * the SAS. Any usage of the SAS must include these query parameters and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @param requestQueryParameters The custom query parameters to be set when the SAS is used. * @return the updated BlobServiceSasSignatureValues object */ From 372cf05fda5d5e927c1953b30da52d0dd1af1eff Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 10:09:35 -0800 Subject: [PATCH 20/37] adding note to datalake sas params too --- .../datalake/sas/DataLakeServiceSasSignatureValues.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java index 54c90d3c04ba..f5b7fe8b78f9 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java @@ -484,6 +484,8 @@ public DataLakeServiceSasSignatureValues setDelegatedUserObjectId(String delegat * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. * Any usage of the SAS must include these headers and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @return The custom request headers to be set when the SAS is used. */ public Map getRequestHeaders() { @@ -494,6 +496,8 @@ public Map getRequestHeaders() { * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. * Any usage of the SAS must include these headers and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @param requestHeaders The custom request headers to be set when the SAS is used. * @return the updated DataLakeServiceSasSignatureValues object */ @@ -506,6 +510,8 @@ public DataLakeServiceSasSignatureValues setRequestHeaders(Map r * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in * the SAS. Any usage of the SAS must include these query parameters and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @return The custom query parameters to be set when the SAS is used. */ public Map getRequestQueryParameters() { @@ -516,6 +522,8 @@ public Map getRequestQueryParameters() { * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in * the SAS. Any usage of the SAS must include these query parameters and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @param requestQueryParameters The custom query parameters to be set when the SAS is used. * @return the updated DataLakeServiceSasSignatureValues object */ From 4a20e60ae710cd55339e1ef01a73bcdbfcc55919 Mon Sep 17 00:00:00 2001 From: browndav Date: Mon, 2 Feb 2026 13:26:17 -0500 Subject: [PATCH 21/37] add header to sasimplutiltests --- .../azure/storage/common/implementation/SasImplUtilsTests.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index d5b39c284562..046592f0bcf3 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + package com.azure.storage.common.implementation; import org.junit.jupiter.api.BeforeEach; From ec472d8a787509aa344db9e5161ec47dcc13c3a1 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 10:30:57 -0800 Subject: [PATCH 22/37] applying spotless --- .../azure/storage/common/implementation/Constants.java | 1 - .../storage/common/implementation/SasImplUtilsTests.java | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java index 3d946dff8461..69fbcd58eae1 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/Constants.java @@ -364,7 +364,6 @@ public static final class UrlConstants { */ public static final String SAS_ENCRYPTION_SCOPE = "ses"; - /** * The SAS request headers parameter. */ diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index 425a7c0316de..c69b9457f693 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. package com.azure.storage.common.implementation; import org.junit.jupiter.api.BeforeEach; @@ -8,7 +10,7 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.assertEquals;; +import static org.junit.jupiter.api.Assertions.assertEquals; public class SasImplUtilsTests { @@ -36,8 +38,9 @@ public void formatRequestHeadersForSasSigningPopulatedHeaders() { requestHeaders.put(Constants.HeaderConstants.CONTENT_TYPE, "contentTypeValue"); requestHeaders.put(Constants.HeaderConstants.CLIENT_REQUEST_ID, "clientRequestId"); - String expected = "x-ms-encryption-key:encryptionKeyValue\n" + "Content-Encoding:contentEncodingValue\n" - + "Content-Type:contentTypeValue\n" + "x-ms-client-request-id:clientRequestId\n"; + String expected + = String.join("\n", "x-ms-encryption-key:encryptionKeyValue", "Content-Encoding:contentEncodingValue", + "Content-Type:contentTypeValue", "x-ms-client-request-id:clientRequestId"); String headers = SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders); Integer newLineCount From 4b1531e8cccaeb5f7406d706d9b90ba982403c2e Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 11:51:56 -0800 Subject: [PATCH 23/37] small refactors in new sas test models --- .../common/sas/CommonSasQueryParameters.java | 4 ++ .../common/test/shared/SasTestData.java | 54 ++++++++++++++----- .../shared/UserDelegationSasTestData.java | 28 ++++++---- .../implementation/SasImplUtilsTests.java | 1 + 4 files changed, 65 insertions(+), 22 deletions(-) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java index c79a1f5b9e54..53beaa44fe9b 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java @@ -501,6 +501,8 @@ public String getDelegatedUserObjectId() { * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. * Any usage of the SAS must include these headers and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @return A map of request headers. */ public Map getRequestHeaders() { @@ -511,6 +513,8 @@ public Map getRequestHeaders() { * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in * the SAS. Any usage of the SAS must include these query parameters and values in the request. * + *

Note: This parameter is only valid for user delegation SAS.

+ * * @return A map of request query parameters. */ public Map getRequestQueryParameters() { diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java index 5fa488b87848..cb3a5de229e9 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java @@ -1,10 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. + package com.azure.storage.common.test.shared; + import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; import org.junit.jupiter.params.provider.Arguments; import java.time.OffsetDateTime; + /** * Helper class to build test arguments for regular SAS string-to-sign tests. * This is the base class that contains common fields shared by both regular SAS and user delegation SAS. @@ -13,58 +16,85 @@ * For user delegation SAS tests, use {@link UserDelegationSasTestData} which extends this class. */ public class SasTestData { - // Common fields for all SAS types - protected OffsetDateTime startTime; - protected SasIpRange ipRange; - protected SasProtocol protocol; - protected String cacheControl; - protected String disposition; - protected String encoding; - protected String language; - protected String type; - protected String expectedStringToSign; - // Regular SAS specific field - protected String identifier; // Signed identifier for regular SAS + private OffsetDateTime startTime; + private SasIpRange ipRange; + private SasProtocol protocol; + private String cacheControl; + private String disposition; + private String encoding; + private String language; + private String type; + private String expectedStringToSign; + private String identifier; + + /** + * Default constructor. + * All fields default to null. + */ + public SasTestData() { + } + public SasTestData setStartTime(OffsetDateTime startTime) { this.startTime = startTime; return this; } + public SasTestData setIdentifier(String identifier) { this.identifier = identifier; return this; } + public SasTestData setIpRange(SasIpRange ipRange) { this.ipRange = ipRange; return this; } + public SasTestData setProtocol(SasProtocol protocol) { this.protocol = protocol; return this; } + public SasTestData setCacheControl(String cacheControl) { this.cacheControl = cacheControl; return this; } + public SasTestData setDisposition(String disposition) { this.disposition = disposition; return this; } + public SasTestData setEncoding(String encoding) { this.encoding = encoding; return this; } + public SasTestData setLanguage(String language) { this.language = language; return this; } + public SasTestData setType(String type) { this.type = type; return this; } + public SasTestData setExpectedStringToSign(String expectedStringToSign) { this.expectedStringToSign = expectedStringToSign; return this; } + + public OffsetDateTime getStartTime() { return startTime; } + public String getIdentifier() { return identifier; } + public SasIpRange getIpRange() { return ipRange; } + public SasProtocol getProtocol() { return protocol; } + public String getCacheControl() { return cacheControl; } + public String getDisposition() { return disposition; } + public String getEncoding() { return encoding; } + public String getLanguage() { return language; } + public String getType() { return type; } + public String getExpectedStringToSign() { return expectedStringToSign; } + /** * Converts to Arguments for regular SAS tests. * Returns arguments in this order: diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java index c90554e1627b..1fac76e107d9 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java @@ -21,7 +21,6 @@ * For regular SAS tests, use {@link SasTestData} directly. */ public class UserDelegationSasTestData extends SasTestData { - // User delegation SAS specific fields private String keyOid; private String keyTid; private OffsetDateTime keyStart; @@ -35,6 +34,14 @@ public class UserDelegationSasTestData extends SasTestData { private String suoid; private String cid; + /** + * Default constructor. + * All fields default to null. + */ + public UserDelegationSasTestData() { + super(); + } + // Override parent setters to return UserDelegationSasTestData for fluent API @Override public UserDelegationSasTestData setStartTime(OffsetDateTime startTime) { @@ -90,8 +97,6 @@ public UserDelegationSasTestData setExpectedStringToSign(String expectedStringTo return this; } - // User delegation SAS specific setters - public UserDelegationSasTestData setKeyOid(String keyOid) { this.keyOid = keyOid; return this; @@ -161,12 +166,17 @@ public UserDelegationSasTestData setCid(String cid) { */ public Arguments toArguments(boolean withHeadersAndParams) { if (withHeadersAndParams) { - return Arguments.of(startTime, keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, - ipRange, protocol, cacheControl, disposition, encoding, language, type, requestHeaders, - requestQueryParameters, saoid, suoid, cid, expectedStringToSign); + return Arguments.of( + getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, + getIpRange(), getProtocol(), getCacheControl(), getDisposition(), getEncoding(), getLanguage(), getType(), + requestHeaders, requestQueryParameters, saoid, suoid, cid, getExpectedStringToSign() + ); } else { - return Arguments.of(startTime, keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, - ipRange, protocol, cacheControl, disposition, encoding, language, type, saoid, suoid, cid, expectedStringToSign); + return Arguments.of( + getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, + getIpRange(), getProtocol(), getCacheControl(), getDisposition(), getEncoding(), getLanguage(), getType(), + saoid, suoid, cid, getExpectedStringToSign() + ); } } @@ -180,5 +190,3 @@ public Arguments toArguments() { return toArguments(true); } } - - diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index 919572bb8bdb..4e1d931455da 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -11,6 +11,7 @@ import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; public class SasImplUtilsTests { From b0500eaf12ec1fd830a046503813677f2bc24d34 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 12:04:09 -0800 Subject: [PATCH 24/37] adding extra comments to SasClientTests --- .../azure/storage/blob/SasClientTests.java | 70 ++++++++++--------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index fdc2f0bd3fcb..95480c10d225 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -569,7 +569,7 @@ public void containerUserDelegationCorrelationId() { String sasWithPermissions = cc.generateUserDelegationSas(sasValues, key); BlobContainerClient client = getContainerClient(sasWithPermissions, cc.getBlobContainerUrl()); - client.listBlobs().iterator().hasNext(); + assertTrue(client.listBlobs().iterator().hasNext()); assertDoesNotThrow(() -> sasWithPermissions.contains("scid=" + cid)); }); @@ -985,6 +985,7 @@ public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identif */ private static Stream blobSasImplUtilStringToSignSupplier() { return Stream.of( + // Start Time Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, null, null, null, null, null, "r\n" @@ -995,62 +996,73 @@ private static Stream blobSasImplUtilStringToSignSupplier() { .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Identifier Arguments.of(null, "id", null, null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Sas IP Range Arguments.of(null, null, new SasIpRange(), null, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Sas Protocol Arguments.of(null, null, null, SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), + // Snapshot ID Arguments.of(null, null, null, null, "snapId", null, null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nbs\nsnapId\n\n\n\n\n\n"), + // Cache Control Arguments.of(null, null, null, null, null, "control", null, null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\ncontrol\n\n\n\n"), + // Content Disposition Arguments.of(null, null, null, null, null, null, "disposition", null, null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\ndisposition\n\n\n"), + // Content Encoding Arguments.of(null, null, null, null, null, null, null, "encoding", null, null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\nencoding\n\n"), + // Content Language Arguments.of(null, null, null, null, null, null, null, null, "language", null, null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\nlanguage\n"), + // Content Type Arguments.of(null, null, null, null, null, null, null, null, null, "type", null, null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\ntype"), + // Version ID Arguments.of(null, null, null, null, null, null, null, null, null, null, "versionId", null, "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nbv\nversionId\n\n\n\n\n\n"), + // Encryption Scope Arguments.of(null, null, null, null, null, null, null, null, null, null, null, "encryptionScope", "r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER @@ -1134,6 +1146,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup multipleQueryParams.put("comp", "blocklist"); return Stream.of( + //StartTime Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -1145,6 +1158,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Key Object ID Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -1153,6 +1167,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Key Tenant ID Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -1161,6 +1176,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Key Start Time Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -1169,6 +1185,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Key Expiry Time Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -1177,6 +1194,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Key Service Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" @@ -1184,6 +1202,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Key Version Arguments.of(null, null, null, null, null, null, "2018-06-17", "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, @@ -1192,6 +1211,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Sas Ip Range Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" @@ -1199,6 +1219,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Sas Protocol Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" @@ -1206,6 +1227,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Snapshot ID Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, "snapId", null, null, null, null, null, null, null, null, null, null, null, null, "r\n\n" @@ -1213,6 +1235,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nbs\nsnapId\n\n\n\n\n\n\n\n"), + // Cache Control Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, "control", null, null, null, null, null, null, null, null, null, null, null, "r\n\n" @@ -1220,6 +1243,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\ncontrol\n\n\n\n"), + // Content Disposition Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, "disposition", null, null, null, null, null, null, null, null, null, null, "r\n\n" @@ -1227,6 +1251,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\ndisposition\n\n\n"), + // Content Encoding Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, "encoding", null, null, null, null, null, null, null, null, null, "r\n\n" @@ -1234,6 +1259,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\nencoding\n\n"), + // Content Language Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, "language", null, null, null, null, null, null, null, null, "r\n\n" @@ -1241,6 +1267,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\nlanguage\n"), + // Content Type Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, "type", null, null, null, null, null, null, null, "r\n\n" @@ -1248,6 +1275,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\ntype"), + // Version ID Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, "versionId", null, null, null, null, null, null, "r\n\n" @@ -1255,6 +1283,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nbv\nversionId\n\n\n\n\n\n\n\n"), + // Saoid - Preauthorized Agent Object ID Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, "saoid", null, null, null, null, null, "r\n\n" @@ -1262,6 +1291,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Correlation ID Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, "cid", null, null, null, null, "r\n\n" @@ -1269,6 +1299,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + // Encryption Scope Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, null, null, "r\n\n" @@ -1276,6 +1307,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\nencryptionScope\n\n\n\n\n\n\n"), + // Delegated User Object ID Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, "r\n\n" @@ -1283,35 +1315,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), - // Test requestHeaders only (single header) + // Request Headers (single header) Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, singleHeader, null, "r\n\n" @@ -1319,7 +1323,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n"), - // Test requestQueryParameters only (single param) + // Request Query Params (single param) Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, singleQueryParam, "r\n\n" @@ -1327,7 +1331,7 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n"), - // Test both requestHeaders and requestQueryParameters + // Request Headers and Query Params (single each) Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, null, null, null, null, singleHeader, singleQueryParam, "r\n\n" @@ -1522,7 +1526,7 @@ private static void assertEqualsForEachLine(ArrayList stringToSign, Stri output.append(actual.replace("\n", "\\n\n")); // Print everything at once - System.out.println(output.toString()); + System.out.println(output); } assertEquals(expected, actual, "String-to-sign mismatch"); } From 99e7232cb9f744e637567a348399b9c98350d0e1 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 12:53:07 -0800 Subject: [PATCH 25/37] applying new sas test model to blob sas tests --- .../azure/storage/blob/SasClientTests.java | 180 ++++++++++-------- .../common/test/shared/SasTestData.java | 25 ++- .../shared/UserDelegationSasTestData.java | 28 ++- .../azure/storage/file/datalake/SasTests.java | 1 + 4 files changed, 144 insertions(+), 90 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 95480c10d225..b3383aa41c27 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -29,6 +29,7 @@ import com.azure.storage.common.sas.CommonSasQueryParameters; import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; +import com.azure.storage.common.test.shared.SasTestData; import com.azure.storage.common.test.shared.StorageCommonTestUtils; import com.azure.storage.common.test.shared.extensions.LiveOnly; import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion; @@ -952,11 +953,7 @@ public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identif v.setStartTime(startTime); - if (ipRange != null) { - SasIpRange ipR = new SasIpRange(); - ipR.setIpMin("ip"); - v.setSasIpRange(ipR); - } + v.setSasIpRange(ipRange); v.setIdentifier(identifier) .setProtocol(protocol) @@ -985,90 +982,105 @@ public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identif */ private static Stream blobSasImplUtilStringToSignSupplier() { return Stream.of( - // Start Time - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - null, null, null, null, null, - "r\n" + //Start Time + new SasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setExpectedStringToSign("r\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - // Identifier - Arguments.of(null, "id", null, null, null, null, null, null, null, null, null, null, "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Sas IP Range - Arguments.of(null, null, new SasIpRange(), null, null, null, null, null, null, null, null, null, "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Sas Protocol - Arguments.of(null, null, null, SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - // Snapshot ID - Arguments.of(null, null, null, null, "snapId", null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n"), - // Cache Control - Arguments.of(null, null, null, null, null, "control", null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n"), - // Content Disposition - Arguments.of(null, null, null, null, null, null, "disposition", null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n"), - // Content Encoding - Arguments.of(null, null, null, null, null, null, null, "encoding", null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n"), - // Content Language - Arguments.of(null, null, null, null, null, null, null, null, "language", null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n"), - // Content Type - Arguments.of(null, null, null, null, null, null, null, null, null, "type", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype"), - // Version ID - Arguments.of(null, null, null, null, null, null, null, null, null, null, "versionId", null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n"), - // Encryption Scope - Arguments.of(null, null, null, null, null, null, null, null, null, null, null, "encryptionScope", - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n")); + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + //.toArguments(), + .toArguments()); + // // Identifier + // new SasTestData().setIdentifier("id") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\n") + // .toArguments(), + // // Sas IP Range + // new SasTestData().setIpRange(new SasIpRange().setIpMin("ip")) + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\n") + // .toArguments(), + // // Sas Protocol + // new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + // .toArguments(), + // // Snapshot ID + // new SasTestData().setSnapshotId("snapId") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nbs\nsnapId\n\n\n\n\n\n") + // .toArguments(), + // // Cache Control + // new SasTestData().setCacheControl("control") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\ncontrol\n\n\n\n") + // .toArguments(), + // // Content Disposition + // new SasTestData().setDisposition("disposition") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\ndisposition\n\n\n") + // .toArguments(), + // // Content Encoding + // new SasTestData().setEncoding("encoding") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\nencoding\n\n") + // .toArguments(), + // // Content Language + // new SasTestData().setLanguage("language") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\nlanguage\n") + // .toArguments(), + // // Content Type + // new SasTestData().setType("type") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\n\n\n\n\n\ntype") + // .toArguments(), + // // Version ID + // new SasTestData().setVersionId("versionId") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nbv\nversionId\n\n\n\n\n\n") + // .toArguments(), + // // Encryption Scope + // new SasTestData().setEncryptionScope("encryptionScope") + // .setExpectedStringToSign("r\n\n" + // + Constants.ISO_8601_UTC_DATE_FORMATTER + // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + // + "\nb\n\nencryptionScope\n\n\n\n\n") + // .toArguments()); } @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java index cb3a5de229e9..9b3a9f4f24f5 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java @@ -19,11 +19,14 @@ public class SasTestData { private OffsetDateTime startTime; private SasIpRange ipRange; private SasProtocol protocol; + private String snapshotId; private String cacheControl; private String disposition; private String encoding; private String language; private String type; + private String versionId; + private String encryptionScope; private String expectedStringToSign; private String identifier; @@ -54,6 +57,11 @@ public SasTestData setProtocol(SasProtocol protocol) { return this; } + public SasTestData setSnapshotId(String snapshotId) { + this.snapshotId = snapshotId; + return this; + } + public SasTestData setCacheControl(String cacheControl) { this.cacheControl = cacheControl; return this; @@ -79,6 +87,16 @@ public SasTestData setType(String type) { return this; } + public SasTestData setVersionId(String versionId) { + this.versionId = versionId; + return this; + } + + public SasTestData setEncryptionScope(String encryptionScope) { + this.encryptionScope = encryptionScope; + return this; + } + public SasTestData setExpectedStringToSign(String expectedStringToSign) { this.expectedStringToSign = expectedStringToSign; return this; @@ -88,11 +106,14 @@ public SasTestData setExpectedStringToSign(String expectedStringToSign) { public String getIdentifier() { return identifier; } public SasIpRange getIpRange() { return ipRange; } public SasProtocol getProtocol() { return protocol; } + public String getSnapshotId() { return snapshotId; } public String getCacheControl() { return cacheControl; } public String getDisposition() { return disposition; } public String getEncoding() { return encoding; } public String getLanguage() { return language; } public String getType() { return type; } + public String getVersionId() { return versionId; } + public String getEncryptionScope() { return encryptionScope; } public String getExpectedStringToSign() { return expectedStringToSign; } /** @@ -103,7 +124,7 @@ public SasTestData setExpectedStringToSign(String expectedStringToSign) { * @return Arguments for parameterized tests matching the signature of regular SAS test methods */ public Arguments toArguments() { - return Arguments.of(startTime, identifier, ipRange, protocol, cacheControl, disposition, encoding, language, - type, expectedStringToSign); + return Arguments.of(startTime, identifier, ipRange, protocol, snapshotId, cacheControl, disposition, encoding, + language, type, versionId, encryptionScope, expectedStringToSign); } } diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java index 1fac76e107d9..03da3a75d1cd 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java @@ -61,6 +61,12 @@ public UserDelegationSasTestData setProtocol(SasProtocol protocol) { return this; } + @Override + public UserDelegationSasTestData setSnapshotId(String snapshotId) { + super.setSnapshotId(snapshotId); + return this; + } + @Override public UserDelegationSasTestData setCacheControl(String cacheControl) { super.setCacheControl(cacheControl); @@ -91,6 +97,18 @@ public UserDelegationSasTestData setType(String type) { return this; } + @Override + public UserDelegationSasTestData setVersionId(String versionId) { + super.setVersionId(versionId); + return this; + } + + @Override + public UserDelegationSasTestData setEncryptionScope(String encryptionScope) { + super.setEncryptionScope(encryptionScope); + return this; + } + @Override public UserDelegationSasTestData setExpectedStringToSign(String expectedStringToSign) { super.setExpectedStringToSign(expectedStringToSign); @@ -168,14 +186,16 @@ public Arguments toArguments(boolean withHeadersAndParams) { if (withHeadersAndParams) { return Arguments.of( getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, - getIpRange(), getProtocol(), getCacheControl(), getDisposition(), getEncoding(), getLanguage(), getType(), - requestHeaders, requestQueryParameters, saoid, suoid, cid, getExpectedStringToSign() + getIpRange(), getProtocol(), getSnapshotId(), getCacheControl(), getDisposition(), getEncoding(), + getLanguage(), getType(), getVersionId(), getEncryptionScope(), requestHeaders, requestQueryParameters, + saoid, suoid, cid, getExpectedStringToSign() ); } else { return Arguments.of( getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, - getIpRange(), getProtocol(), getCacheControl(), getDisposition(), getEncoding(), getLanguage(), getType(), - saoid, suoid, cid, getExpectedStringToSign() + getIpRange(), getProtocol(), getSnapshotId(), getCacheControl(), getDisposition(), getEncoding(), + getLanguage(), getType(), getVersionId(), getEncryptionScope(), saoid, suoid, cid, + getExpectedStringToSign() ); } } diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 8984681b6388..25a304e0deb6 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -890,6 +890,7 @@ private static Stream sasImplUtilStringToSignUserDelegationKeySupplie // We test string to sign functionality directly related to user delegation sas specific parameters return Stream.of( + // Start time new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER From b2d826125b262bc16772417902c70a7d063bfc67 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 12:53:49 -0800 Subject: [PATCH 26/37] returning null instead of empty string during formatting --- .../com/azure/storage/common/implementation/SasImplUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java index 17aa7ffc0d17..3708c442496c 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java @@ -132,7 +132,7 @@ public static Map parseQueryString(String queryParams) { public static String formatRequestHeadersForSasSigning(Map requestHeaders) { if (requestHeaders == null || requestHeaders.isEmpty()) { - return ""; + return null; } StringBuilder sb = new StringBuilder(); requestHeaders.forEach((key, value) -> sb.append(key).append(":").append(value).append("\n")); @@ -151,7 +151,7 @@ public static String formatRequestHeadersForSasSigning(Map reque */ public static String formatRequestQueryParametersForSasSigning(Map requestQueryParameters) { if (requestQueryParameters == null || requestQueryParameters.isEmpty()) { - return ""; + return null; } StringBuilder sb = new StringBuilder(); requestQueryParameters.forEach((key, value) -> sb.append("\n").append(key).append(":").append(value)); From 136b7f7fea052e18a023071ca34cf8be93079ec0 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Mon, 2 Feb 2026 14:09:25 -0800 Subject: [PATCH 27/37] applying new sas test model to blob sas tests --- .../azure/storage/blob/SasClientTests.java | 463 +++++++++--------- .../shared/UserDelegationSasTestData.java | 35 +- .../implementation/SasImplUtilsTests.java | 17 +- 3 files changed, 259 insertions(+), 256 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index b3383aa41c27..b64d1452d5b6 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -31,6 +31,7 @@ import com.azure.storage.common.sas.SasProtocol; import com.azure.storage.common.test.shared.SasTestData; import com.azure.storage.common.test.shared.StorageCommonTestUtils; +import com.azure.storage.common.test.shared.UserDelegationSasTestData; import com.azure.storage.common.test.shared.extensions.LiveOnly; import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion; import org.junit.jupiter.api.BeforeEach; @@ -991,96 +992,95 @@ private static Stream blobSasImplUtilStringToSignSupplier() { + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - //.toArguments(), + .toArguments(), + // Identifier + new SasTestData().setIdentifier("id") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n") + .toArguments(), + // Sas IP Range + new SasTestData().setIpRange(new SasIpRange().setIpMin("ip")) + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n") + .toArguments(), + // Sas Protocol + new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toArguments(), + // Snapshot ID + new SasTestData().setSnapshotId("snapId") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbs\nsnapId\n\n\n\n\n\n") + .toArguments(), + // Cache Control + new SasTestData().setCacheControl("control") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\ncontrol\n\n\n\n") + .toArguments(), + // Content Disposition + new SasTestData().setDisposition("disposition") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\ndisposition\n\n\n") + .toArguments(), + // Content Encoding + new SasTestData().setEncoding("encoding") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\nencoding\n\n") + .toArguments(), + // Content Language + new SasTestData().setLanguage("language") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\nlanguage\n") + .toArguments(), + // Content Type + new SasTestData().setType("type") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\ntype") + .toArguments(), + // Version ID + new SasTestData().setVersionId("versionId") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbv\nversionId\n\n\n\n\n\n") + .toArguments(), + // Encryption Scope + new SasTestData().setEncryptionScope("encryptionScope") + .setExpectedStringToSign("r\n\n" + + Constants.ISO_8601_UTC_DATE_FORMATTER + .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\nencryptionScope\n\n\n\n\n") .toArguments()); - // // Identifier - // new SasTestData().setIdentifier("id") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\n") - // .toArguments(), - // // Sas IP Range - // new SasTestData().setIpRange(new SasIpRange().setIpMin("ip")) - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\n") - // .toArguments(), - // // Sas Protocol - // new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - // + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - // .toArguments(), - // // Snapshot ID - // new SasTestData().setSnapshotId("snapId") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nbs\nsnapId\n\n\n\n\n\n") - // .toArguments(), - // // Cache Control - // new SasTestData().setCacheControl("control") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\ncontrol\n\n\n\n") - // .toArguments(), - // // Content Disposition - // new SasTestData().setDisposition("disposition") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\ndisposition\n\n\n") - // .toArguments(), - // // Content Encoding - // new SasTestData().setEncoding("encoding") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\nencoding\n\n") - // .toArguments(), - // // Content Language - // new SasTestData().setLanguage("language") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\nlanguage\n") - // .toArguments(), - // // Content Type - // new SasTestData().setType("type") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\n\n\n\n\n\ntype") - // .toArguments(), - // // Version ID - // new SasTestData().setVersionId("versionId") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nbv\nversionId\n\n\n\n\n\n") - // .toArguments(), - // // Encryption Scope - // new SasTestData().setEncryptionScope("encryptionScope") - // .setExpectedStringToSign("r\n\n" - // + Constants.ISO_8601_UTC_DATE_FORMATTER - // .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - // + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - // + "\nb\n\nencryptionScope\n\n\n\n\n") - // .toArguments()); } @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @@ -1100,12 +1100,7 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim String expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); v.setStartTime(startTime); - - if (ipRange != null) { - SasIpRange ipR = new SasIpRange(); - ipR.setIpMin("ip"); - v.setSasIpRange(ipR); - } + v.setSasIpRange(ipRange); v.setProtocol(protocol) .setCacheControl(cacheControl) @@ -1159,233 +1154,254 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup return Stream.of( //StartTime - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n" + new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Key Object ID - Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setKeyOid("11111111-1111-1111-1111-111111111111") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Key Tenant ID - Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setKeyTid("22222222-2222-2222-2222-222222222222") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Key Start Time - Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData() + .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Key Expiry Time - Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData() + .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Key Service - Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setKeyService("b") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Key Version - Arguments.of(null, null, null, null, null, null, "2018-06-17", - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setKeyVersion("2018-06-17") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Sas Ip Range - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", - new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setIpRange(new SasIpRange().setIpMin("ip")) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Sas Protocol - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setProtocol(SasProtocol.HTTPS_ONLY) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Snapshot ID - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, "snapId", null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setSnapshotId("snapId") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n\n\n"), + + "\nbs\nsnapId\n\n\n\n\n\n\n\n") + .toArguments(), // Cache Control - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, "control", null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setCacheControl("control") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\ncontrol\n\n\n\n"), + + "\nb\n\n\n\n\ncontrol\n\n\n\n") + .toArguments(), // Content Disposition - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, "disposition", null, null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setDisposition("disposition") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\ndisposition\n\n\n"), + + "\nb\n\n\n\n\n\ndisposition\n\n\n") + .toArguments(), // Content Encoding - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, "encoding", null, null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setEncoding("encoding") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\nencoding\n\n"), + + "\nb\n\n\n\n\n\n\nencoding\n\n") + .toArguments(), // Content Language - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, "language", null, null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setLanguage("language") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\nlanguage\n"), + + "\nb\n\n\n\n\n\n\n\nlanguage\n") + .toArguments(), // Content Type - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, "type", null, null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setType("type") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\ntype"), + + "\nb\n\n\n\n\n\n\n\n\ntype") + .toArguments(), // Version ID - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, "versionId", null, null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setVersionId("versionId") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n\n\n"), + + "\nbv\nversionId\n\n\n\n\n\n\n\n") + .toArguments(), // Saoid - Preauthorized Agent Object ID - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, "saoid", null, null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setSaoid("saoid") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Correlation ID - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, "cid", null, null, null, null, - "r\n\n" + new UserDelegationSasTestData().setCid("cid") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n"), + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Encryption Scope - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, null, null, - "r\n\n" + new UserDelegationSasTestData().setEncryptionScope("encryptionScope") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n\n\n"), + + "\nb\n\nencryptionScope\n\n\n\n\n\n\n") + .toArguments(), // Delegated User Object ID - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", null, null, - "r\n\n" + new UserDelegationSasTestData().setDelegatedOid("delegatedOid") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n"), + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), // Request Headers (single header) - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, singleHeader, null, - "r\n\n" + new UserDelegationSasTestData().setRequestHeaders(singleHeader) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n"), + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n") + .toArguments(), // Request Query Params (single param) - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, null, singleQueryParam, - "r\n\n" + new UserDelegationSasTestData().setRequestQueryParameters(singleQueryParam) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n"), + + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n") + .toArguments(), // Request Headers and Query Params (single each) - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, singleHeader, singleQueryParam, - "r\n\n" + new UserDelegationSasTestData().setRequestQueryParameters(singleQueryParam) + .setRequestHeaders(singleHeader) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n"), + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n") + .toArguments(), // Test multiple headers and multiple query parameters - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, multipleHeaders, - multipleQueryParams, - "r\n\n" + new UserDelegationSasTestData().setRequestHeaders(multipleHeaders) + .setRequestQueryParameters(multipleQueryParams) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" - + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n"), + + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n") + .toArguments(), // Test with all parameters populated - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), // startTime - "11111111-1111-1111-1111-111111111111", // keyOid - "22222222-2222-2222-2222-222222222222", // keyTid - OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), // keyStart - OffsetDateTime.of(LocalDateTime.of(2018, 6, 1, 0, 0), ZoneOffset.UTC), // keyExpiry - "b", // keyService - "2018-06-17", // keyVersion - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", // keyValue - new SasIpRange(), // ipRange - SasProtocol.HTTPS_ONLY, // protocol - "snapId", // snapId - "control", // cacheControl - "disposition", // contentDisposition - "encoding", // contentEncoding - "language", // contentLanguage - "type", // contentType - null, // versionId, versionId and snapId are mutually exclusive - "saoid", // saoid (preauthorizedAgentObjectId) - "cid", // cid (correlationId) - "encryptionScope", // encryptionScope - "delegatedOid", // delegatedUserObjectId - multipleHeaders, // requestHeaders - multipleQueryParams, // requestQueryParameters - "r\n" // permissions + new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setKeyOid("11111111-1111-1111-1111-111111111111") + .setKeyTid("22222222-2222-2222-2222-222222222222") + .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 6, 1, 0, 0), ZoneOffset.UTC)) + .setKeyService("b") + .setKeyVersion("2018-06-17") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setIpRange(new SasIpRange().setIpMin("ip")) + .setProtocol(SasProtocol.HTTPS_ONLY) + .setSnapshotId("snapId") + .setCacheControl("control") + .setDisposition("disposition") + .setEncoding("encoding") + .setLanguage("language") + .setType("type") + .setVersionId(null) // versionId and snapId are mutually exclusive + .setSaoid("saoid") + .setCid("cid") + .setEncryptionScope("encryptionScope") + .setDelegatedOid("delegatedOid") + .setRequestHeaders(multipleHeaders) + .setRequestQueryParameters(multipleQueryParams) + .setExpectedStringToSign("r\n" // permissions + Constants.ISO_8601_UTC_DATE_FORMATTER .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) // startTime + "\n" @@ -1418,7 +1434,8 @@ private static Stream blobSasImplUtilStringToSignUserDelegationKeySup + "encoding\n" // contentEncoding + "language\n" // contentLanguage + "type" // contentType (no trailing newline) - )); + ) + .toArguments()); } @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java index 03da3a75d1cd..3e27d2a55e8b 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java @@ -33,6 +33,7 @@ public class UserDelegationSasTestData extends SasTestData { private String saoid; private String suoid; private String cid; + private String delegatedOid; /** * Default constructor. @@ -175,38 +176,22 @@ public UserDelegationSasTestData setCid(String cid) { return this; } - /** - * Converts to Arguments for user delegation SAS tests. - * Returns arguments with or without request headers/query parameters based on the parameter. - * - * @param withHeadersAndParams Whether to include request headers and query parameters in the test data. - * @return Arguments for parameterized tests matching the signature of user delegation SAS test methods - */ - public Arguments toArguments(boolean withHeadersAndParams) { - if (withHeadersAndParams) { - return Arguments.of( - getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, - getIpRange(), getProtocol(), getSnapshotId(), getCacheControl(), getDisposition(), getEncoding(), - getLanguage(), getType(), getVersionId(), getEncryptionScope(), requestHeaders, requestQueryParameters, - saoid, suoid, cid, getExpectedStringToSign() - ); - } else { - return Arguments.of( - getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, - getIpRange(), getProtocol(), getSnapshotId(), getCacheControl(), getDisposition(), getEncoding(), - getLanguage(), getType(), getVersionId(), getEncryptionScope(), saoid, suoid, cid, - getExpectedStringToSign() - ); - } + public UserDelegationSasTestData setDelegatedOid(String delegatedOid) { + this.delegatedOid = delegatedOid; + return this; } /** * Converts to Arguments for user delegation SAS tests with request headers and query parameters. - * This is a convenience method that calls {@link #toArguments(boolean)} with true. * * @return Arguments for parameterized tests with headers and query parameters included */ public Arguments toArguments() { - return toArguments(true); + return Arguments.of( + getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, + getIpRange(), getProtocol(), getSnapshotId(), getCacheControl(), getDisposition(), getEncoding(), + getLanguage(), getType(), getVersionId(), saoid, cid, + getEncryptionScope(), delegatedOid, requestHeaders, requestQueryParameters, getExpectedStringToSign() + ); } } diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index 4e1d931455da..45f338ddfbff 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -12,6 +12,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class SasImplUtilsTests { @@ -25,13 +26,13 @@ public void setup() { } @Test - public void formatRequestHeadersForSasSigningNullReturnsEmptyString() { - assertEquals("", SasImplUtils.formatRequestHeadersForSasSigning(null)); + public void formatRequestHeadersForSasSigningNullReturnsNull() { + assertNull(SasImplUtils.formatRequestHeadersForSasSigning(null)); } @Test - public void formatRequestHeadersForSasSigningEmptyReturnsEmptyString() { - assertEquals("", SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders)); + public void formatRequestHeadersForSasSigningEmptyReturnsNull() { + assertNull(SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders)); } @Test @@ -67,13 +68,13 @@ public void formatRequestHeadersForSasSigningPopulatedHeaders() { } @Test - public void formatRequestQueryParamsForSasSigningNullReturnsEmptyString() { - assertEquals("", SasImplUtils.formatRequestQueryParametersForSasSigning(null)); + public void formatRequestQueryParamsForSasSigningNullReturnsNull() { + assertNull(SasImplUtils.formatRequestQueryParametersForSasSigning(null)); } @Test - public void formatRequestQueryParamsForSasSigningEmptyReturnsEmptyString() { - assertEquals("", SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams)); + public void formatRequestQueryParamsForSasSigningEmptyReturnsNull() { + assertNull(SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams)); } @Test From 12a968c8eb18248defd1d22c0aeb5ad9670680f1 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Tue, 3 Feb 2026 12:44:25 -0800 Subject: [PATCH 28/37] getting suppliers to use new models --- .../storage/blob/SasAsyncClientTests.java | 275 +--------- .../azure/storage/blob/SasClientTests.java | 436 +--------------- .../common/test/shared/SasTestData.java | 152 ++++++ .../shared/UserDelegationSasTestData.java | 479 +++++++++++++++++- .../DataLakeServiceSasSignatureValues.java | 1 - .../azure/storage/file/datalake/SasTests.java | 243 +-------- 6 files changed, 647 insertions(+), 939 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 86b9c91304fc..613dff661a2b 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -1027,7 +1027,7 @@ private Mono getUserDelegationInfo() { */ @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest - @MethodSource("blobSasImplUtilStringToSignSupplier") + @MethodSource("com.azure.storage.common.test.shared.SasTestData#blobSasImplUtilStringToSignSupplier") public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identifier, SasIpRange ipRange, SasProtocol protocol, String snapId, String cacheControl, String disposition, String encoding, String language, String type, String versionId, String encryptionScope, String expectedStringToSign) { @@ -1038,15 +1038,9 @@ public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identif String expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); - v.setStartTime(startTime); - - if (ipRange != null) { - SasIpRange ipR = new SasIpRange(); - ipR.setIpMin("ip"); - v.setSasIpRange(ipR); - } - - v.setIdentifier(identifier) + v.setStartTime(startTime) + .setSasIpRange(ipRange) + .setIdentifier(identifier) .setProtocol(protocol) .setCacheControl(cacheControl) .setContentDisposition(disposition) @@ -1065,111 +1059,24 @@ public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identif assertEquals(token.getSignature(), ENVIRONMENT.getPrimaryAccount().getCredential().computeHmac256(expected)); } - /* - We don't test the blob or containerName properties because canonicalized resource is always added as at least - /blob/accountName. We test canonicalization of resources later. Again, this is not to test a fully functional - sas but the construction of the string to sign. - Signed resource is tested elsewhere, as we work some minor magic in choosing which value to use. - */ - private static Stream blobSasImplUtilStringToSignSupplier() { - return Stream.of( - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - null, null, null, null, null, - "r\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, "id", null, null, null, null, null, null, null, null, null, null, "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, new SasIpRange(), null, null, null, null, null, null, null, null, null, "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, "snapId", null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, "control", null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, "disposition", null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "encoding", null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n"), - Arguments.of(null, null, null, null, null, null, null, null, "language", null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n"), - Arguments.of(null, null, null, null, null, null, null, null, null, "type", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype"), - Arguments.of(null, null, null, null, null, null, null, null, null, null, "versionId", null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, null, null, null, null, "encryptionScope", - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n")); - } - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest - @MethodSource("blobSasImplUtilStringToSignUserDelegationKeySupplier") + @MethodSource("com.azure.storage.common.test.shared.UserDelegationSasTestData#blobSasImplUtilStringToSignUserDelegationKeySupplier") public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, String keyOid, String keyTid, OffsetDateTime keyStart, OffsetDateTime keyExpiry, String keyService, String keyVersion, String keyValue, SasIpRange ipRange, SasProtocol protocol, String snapId, String cacheControl, String disposition, String encoding, String language, String type, String versionId, String saoid, String cid, - String encryptionScope, String delegatedUserObjectId, String expectedStringToSign) { + String encryptionScope, String delegatedUserObjectId, Map requestHeaders, + Map requestQueryParameters, String expectedStringToSign) { OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); BlobSasPermission p = new BlobSasPermission().setReadPermission(true); BlobServiceSasSignatureValues v = new BlobServiceSasSignatureValues(e, p); String expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); - v.setStartTime(startTime); - - if (ipRange != null) { - SasIpRange ipR = new SasIpRange(); - ipR.setIpMin("ip"); - v.setSasIpRange(ipR); - } - - v.setProtocol(protocol) + v.setStartTime(startTime) + .setSasIpRange(ipRange) + .setProtocol(protocol) .setCacheControl(cacheControl) .setContentDisposition(disposition) .setContentEncoding(encoding) @@ -1177,7 +1084,9 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim .setContentType(type) .setPreauthorizedAgentObjectId(saoid) .setCorrelationId(cid) - .setDelegatedUserObjectId(delegatedUserObjectId); + .setDelegatedUserObjectId(delegatedUserObjectId) + .setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParameters); UserDelegationKey key = new UserDelegationKey().setSignedObjectId(keyOid) .setSignedTenantId(keyTid) @@ -1192,167 +1101,11 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim String sasToken = implUtil.generateUserDelegationSas(key, ENVIRONMENT.getPrimaryAccount().getName(), Context.NONE); CommonSasQueryParameters token - = BlobUrlParts.parse(cc.getBlobContainerUrl() + "?" + sasToken).getCommonSasQueryParameters(); + = BlobUrlParts.parse(ccAsync.getBlobContainerUrl() + "?" + sasToken).getCommonSasQueryParameters(); assertEquals(token.getSignature(), StorageImplUtils.computeHMac256(key.getValue(), expected)); } - /* - We test string to sign functionality directly related toUserDelegation sas specific parameters - */ - private static Stream blobSasImplUtilStringToSignUserDelegationKeySupplier() { - return Stream.of( - Arguments.of(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), null, null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, "11111111-1111-1111-1111-111111111111", null, null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, "22222222-2222-2222-2222-222222222222", null, null, null, null, - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), null, - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC), - null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, - null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, "b", null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, "2018-06-17", - "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, null, null, null, null, null, null, null, null, - null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", - new SasIpRange(), null, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - SasProtocol.HTTPS_ONLY, null, null, null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, "snapId", null, null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, "control", null, null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, "disposition", null, null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, "encoding", null, null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, "language", null, null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, "type", null, null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, "versionId", null, null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, "saoid", null, null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, "cid", null, null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, "encryptionScope", null, - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n"), - Arguments.of(null, null, null, null, null, null, null, "3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=", null, - null, null, null, null, null, null, null, null, null, null, null, "delegatedOid", - "r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n")); - } - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest @MethodSource("blobSasImplUtilCanonicalizedResourceSupplier") diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index b64d1452d5b6..8e5f68cf61b1 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -29,9 +29,7 @@ import com.azure.storage.common.sas.CommonSasQueryParameters; import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; -import com.azure.storage.common.test.shared.SasTestData; import com.azure.storage.common.test.shared.StorageCommonTestUtils; -import com.azure.storage.common.test.shared.UserDelegationSasTestData; import com.azure.storage.common.test.shared.extensions.LiveOnly; import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion; import org.junit.jupiter.api.BeforeEach; @@ -44,12 +42,10 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Stream; @@ -941,7 +937,7 @@ private UserDelegationKey getUserDelegationInfo() { @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest - @MethodSource("blobSasImplUtilStringToSignSupplier") + @MethodSource("com.azure.storage.common.test.shared.SasTestData#blobSasImplUtilStringToSignSupplier") public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identifier, SasIpRange ipRange, SasProtocol protocol, String snapId, String cacheControl, String disposition, String encoding, String language, String type, String versionId, String encryptionScope, String expectedStringToSign) { @@ -952,11 +948,9 @@ public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identif String expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); - v.setStartTime(startTime); - - v.setSasIpRange(ipRange); - - v.setIdentifier(identifier) + v.setStartTime(startTime) + .setSasIpRange(ipRange) + .setIdentifier(identifier) .setProtocol(protocol) .setCacheControl(cacheControl) .setContentDisposition(disposition) @@ -975,117 +969,9 @@ public void blobSasImplUtilStringToSign(OffsetDateTime startTime, String identif assertEquals(token.getSignature(), ENVIRONMENT.getPrimaryAccount().getCredential().computeHmac256(expected)); } - /* - We don't test the blob or containerName properties because canonicalized resource is always added as at least - /blob/accountName. We test canonicalization of resources later. Again, this is not to test a fully functional - sas but the construction of the string to sign. - Signed resource is tested elsewhere, as we work some minor magic in choosing which value to use. - */ - private static Stream blobSasImplUtilStringToSignSupplier() { - return Stream.of( - //Start Time - new SasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - .setExpectedStringToSign("r\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - .toArguments(), - // Identifier - new SasTestData().setIdentifier("id") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n") - .toArguments(), - // Sas IP Range - new SasTestData().setIpRange(new SasIpRange().setIpMin("ip")) - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n") - .toArguments(), - // Sas Protocol - new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - .toArguments(), - // Snapshot ID - new SasTestData().setSnapshotId("snapId") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n") - .toArguments(), - // Cache Control - new SasTestData().setCacheControl("control") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\ncontrol\n\n\n\n") - .toArguments(), - // Content Disposition - new SasTestData().setDisposition("disposition") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\ndisposition\n\n\n") - .toArguments(), - // Content Encoding - new SasTestData().setEncoding("encoding") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\nencoding\n\n") - .toArguments(), - // Content Language - new SasTestData().setLanguage("language") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\nlanguage\n") - .toArguments(), - // Content Type - new SasTestData().setType("type") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\ntype") - .toArguments(), - // Version ID - new SasTestData().setVersionId("versionId") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n") - .toArguments(), - // Encryption Scope - new SasTestData().setEncryptionScope("encryptionScope") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n") - .toArguments()); - } - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest - @MethodSource("blobSasImplUtilStringToSignUserDelegationKeySupplier") + @MethodSource("com.azure.storage.common.test.shared.UserDelegationSasTestData#blobSasImplUtilStringToSignUserDelegationKeySupplier") public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, String keyOid, String keyTid, OffsetDateTime keyStart, OffsetDateTime keyExpiry, String keyService, String keyVersion, String keyValue, SasIpRange ipRange, SasProtocol protocol, String snapId, String cacheControl, String disposition, @@ -1099,10 +985,9 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim String expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); - v.setStartTime(startTime); - v.setSasIpRange(ipRange); - - v.setProtocol(protocol) + v.setStartTime(startTime) + .setSasIpRange(ipRange) + .setProtocol(protocol) .setCacheControl(cacheControl) .setContentDisposition(disposition) .setContentEncoding(encoding) @@ -1133,311 +1018,6 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim assertEquals(token.getSignature(), StorageImplUtils.computeHMac256(key.getValue(), expected)); } - /* - We test string to sign functionality directly related toUserDelegation sas specific parameters - */ - private static Stream blobSasImplUtilStringToSignUserDelegationKeySupplier() { - // Use LinkedHashMap to ensure deterministic iteration order - Map singleHeader = new LinkedHashMap<>(); - singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); - - Map singleQueryParam = new LinkedHashMap<>(); - singleQueryParam.put("comp", "blocklist"); - - Map multipleHeaders = new LinkedHashMap<>(); - multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); - multipleHeaders.put("x-ms-source-if-match", "etag"); - - Map multipleQueryParams = new LinkedHashMap<>(); - multipleQueryParams.put("blockid", "blockidvalue"); - multipleQueryParams.put("comp", "blocklist"); - - return Stream.of( - //StartTime - new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Key Object ID - new UserDelegationSasTestData().setKeyOid("11111111-1111-1111-1111-111111111111") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Key Tenant ID - new UserDelegationSasTestData().setKeyTid("22222222-2222-2222-2222-222222222222") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Key Start Time - new UserDelegationSasTestData() - .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Key Expiry Time - new UserDelegationSasTestData() - .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Key Service - new UserDelegationSasTestData().setKeyService("b") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Key Version - new UserDelegationSasTestData().setKeyVersion("2018-06-17") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Sas Ip Range - new UserDelegationSasTestData().setIpRange(new SasIpRange().setIpMin("ip")) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Sas Protocol - new UserDelegationSasTestData().setProtocol(SasProtocol.HTTPS_ONLY) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Snapshot ID - new UserDelegationSasTestData().setSnapshotId("snapId") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbs\nsnapId\n\n\n\n\n\n\n\n") - .toArguments(), - // Cache Control - new UserDelegationSasTestData().setCacheControl("control") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\ncontrol\n\n\n\n") - .toArguments(), - // Content Disposition - new UserDelegationSasTestData().setDisposition("disposition") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\ndisposition\n\n\n") - .toArguments(), - // Content Encoding - new UserDelegationSasTestData().setEncoding("encoding") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\nencoding\n\n") - .toArguments(), - // Content Language - new UserDelegationSasTestData().setLanguage("language") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\nlanguage\n") - .toArguments(), - // Content Type - new UserDelegationSasTestData().setType("type") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\ntype") - .toArguments(), - // Version ID - new UserDelegationSasTestData().setVersionId("versionId") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nbv\nversionId\n\n\n\n\n\n\n\n") - .toArguments(), - // Saoid - Preauthorized Agent Object ID - new UserDelegationSasTestData().setSaoid("saoid") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Correlation ID - new UserDelegationSasTestData().setCid("cid") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Encryption Scope - new UserDelegationSasTestData().setEncryptionScope("encryptionScope") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\nencryptionScope\n\n\n\n\n\n\n") - .toArguments(), - // Delegated User Object ID - new UserDelegationSasTestData().setDelegatedOid("delegatedOid") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - // Request Headers (single header) - new UserDelegationSasTestData().setRequestHeaders(singleHeader) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n") - .toArguments(), - // Request Query Params (single param) - new UserDelegationSasTestData().setRequestQueryParameters(singleQueryParam) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n") - .toArguments(), - // Request Headers and Query Params (single each) - new UserDelegationSasTestData().setRequestQueryParameters(singleQueryParam) - .setRequestHeaders(singleHeader) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n") - .toArguments(), - // Test multiple headers and multiple query parameters - new UserDelegationSasTestData().setRequestHeaders(multipleHeaders) - .setRequestQueryParameters(multipleQueryParams) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" - + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n") - .toArguments(), - // Test with all parameters populated - new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - .setKeyOid("11111111-1111-1111-1111-111111111111") - .setKeyTid("22222222-2222-2222-2222-222222222222") - .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) - .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 6, 1, 0, 0), ZoneOffset.UTC)) - .setKeyService("b") - .setKeyVersion("2018-06-17") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setIpRange(new SasIpRange().setIpMin("ip")) - .setProtocol(SasProtocol.HTTPS_ONLY) - .setSnapshotId("snapId") - .setCacheControl("control") - .setDisposition("disposition") - .setEncoding("encoding") - .setLanguage("language") - .setType("type") - .setVersionId(null) // versionId and snapId are mutually exclusive - .setSaoid("saoid") - .setCid("cid") - .setEncryptionScope("encryptionScope") - .setDelegatedOid("delegatedOid") - .setRequestHeaders(multipleHeaders) - .setRequestQueryParameters(multipleQueryParams) - .setExpectedStringToSign("r\n" // permissions - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) // startTime - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) // expiryTime - + "\n/blob/%s/containerName/blobName\n" // canonicalName - + "11111111-1111-1111-1111-111111111111\n" // keyOid - + "22222222-2222-2222-2222-222222222222\n" // keyTid - + "2018-01-01T00:00:00Z\n" // keyStart - + "2018-06-01T00:00:00Z\n" // keyExpiry - + "b\n" // keyService - + "2018-06-17\n" // keyVersion - + "saoid\n" // saoid (preauthorizedAgentObjectId) - + "\n" // suoid (always empty) - + "cid\n" // cid (correlationId) - + "\n" // delegatedUserTenantId (removed - empty) - + "delegatedOid\n" // delegatedUserObjectId - + "ip\n" // sasIpRange - + SasProtocol.HTTPS_ONLY + "\n" // protocol - + Constants.SAS_SERVICE_VERSION + "\n" // VERSION - + "bs\n" // resource (blob snapshot) - + "snapId\n" // snapId (versionSegment with snapId) - + "encryptionScope\n" // encryptionScope - + "x-ms-encryption-key-sha256:hashvalue\n" // requestHeaders (multiple) - + "x-ms-source-if-match:etag\n\n" // requestHeaders continuation + newline separator - + "\nblockid:blockidvalue\n" // requestQueryParameters (multiple, with prepended newline) - + "comp:blocklist\n" // requestQueryParameters continuation - + "control\n" // cacheControl - + "disposition\n" // contentDisposition - + "encoding\n" // contentEncoding - + "language\n" // contentLanguage - + "type" // contentType (no trailing newline) - ) - .toArguments()); - } - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2020-12-06") @ParameterizedTest @MethodSource("blobSasImplUtilCanonicalizedResourceSupplier") diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java index 9b3a9f4f24f5..15ce031e6b7d 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java @@ -3,10 +3,13 @@ package com.azure.storage.common.test.shared; +import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; import org.junit.jupiter.params.provider.Arguments; import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.stream.Stream; /** * Helper class to build test arguments for regular SAS string-to-sign tests. @@ -127,4 +130,153 @@ public Arguments toArguments() { return Arguments.of(startTime, identifier, ipRange, protocol, snapshotId, cacheControl, disposition, encoding, language, type, versionId, encryptionScope, expectedStringToSign); } + + public Arguments toDataLakeArguments() { + return Arguments.of(startTime, identifier, ipRange, protocol, cacheControl, disposition, encoding, language, + type, expectedStringToSign); + } + + /* + We don't test the blob or containerName properties because canonicalized resource is always added as at least + /blob/accountName. We test canonicalization of resources later. Again, this is not to test a fully functional + sas but the construction of the string to sign. + Signed resource is tested elsewhere, as we work some minor magic in choosing which value to use. + */ + public static Stream blobSasImplUtilStringToSignSupplier() { + OffsetDateTime expiryTime = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + String expiryTimeStr = Constants.ISO_8601_UTC_DATE_FORMATTER.format(expiryTime); + + return Stream.of( + //Start Time + new SasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setExpectedStringToSign("r\n" + + expiryTimeStr + + "\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toArguments(), + // Identifier + new SasTestData().setIdentifier("id") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\nid\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n") + .toArguments(), + // Sas IP Range + new SasTestData().setIpRange(new SasIpRange().setIpMin("ip")) + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n") + .toArguments(), + // Sas Protocol + new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toArguments(), + // Snapshot ID + new SasTestData().setSnapshotId("snapId") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbs\nsnapId\n\n\n\n\n\n") + .toArguments(), + // Cache Control + new SasTestData().setCacheControl("control") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\ncontrol\n\n\n\n") + .toArguments(), + // Content Disposition + new SasTestData().setDisposition("disposition") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\ndisposition\n\n\n") + .toArguments(), + // Content Encoding + new SasTestData().setEncoding("encoding") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\nencoding\n\n") + .toArguments(), + // Content Language + new SasTestData().setLanguage("language") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\nlanguage\n") + .toArguments(), + // Content Type + new SasTestData().setType("type") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\ntype") + .toArguments(), + // Version ID + new SasTestData().setVersionId("versionId") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbv\nversionId\n\n\n\n\n\n") + .toArguments(), + // Encryption Scope + new SasTestData().setEncryptionScope("encryptionScope") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\nencryptionScope\n\n\n\n\n") + .toArguments()); + } + + public static Stream dataLakeSasImplUtilStringToSignSupplier() { + // We don't test the blob or containerName properties because canonicalized resource is always added as at least + // /blob/accountName. We test canonicalization of resources later. Again, this is not to test a fully functional + // sas but the construction of the string to sign. + // Signed resource is tested elsewhere, as we work some minor magic in choosing which value to use. + OffsetDateTime expiryTime = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + String expiryTimeStr = Constants.ISO_8601_UTC_DATE_FORMATTER.format(expiryTime); + + return Stream.of(new SasTestData().setStartTime(expiryTime) + .setExpectedStringToSign("r\n" + expiryTimeStr + "\n" + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toDataLakeArguments(), + new SasTestData().setIdentifier("id") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\nid\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toDataLakeArguments(), + new SasTestData().setIpRange(new SasIpRange()) + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\nip\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toDataLakeArguments(), + new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n" + + SasProtocol.HTTPS_ONLY + "\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") + .toDataLakeArguments(), + new SasTestData().setCacheControl("control") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\ncontrol\n\n\n\n") + .toDataLakeArguments(), + new SasTestData().setDisposition("disposition") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\ndisposition\n\n\n") + .toDataLakeArguments(), + new SasTestData().setEncoding("encoding") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\nencoding\n\n") + .toDataLakeArguments(), + new SasTestData().setLanguage("language") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\nlanguage\n") + .toDataLakeArguments(), + new SasTestData().setType("type") + .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\ntype") + .toDataLakeArguments()); + } } diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java index 3e27d2a55e8b..97702d1373cf 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java @@ -3,12 +3,17 @@ package com.azure.storage.common.test.shared; +import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; import org.junit.jupiter.params.provider.Arguments; +import java.time.LocalDateTime; import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Stream; /** * Helper class to build test arguments for User Delegation SAS string-to-sign tests. @@ -30,10 +35,10 @@ public class UserDelegationSasTestData extends SasTestData { private String keyValue; private Map requestHeaders; private Map requestQueryParameters; - private String saoid; - private String suoid; - private String cid; - private String delegatedOid; + private String preauthorizedAgentObjectId; + private String agentObjectId; + private String correlationId; + private String delegatedUserObjectId; /** * Default constructor. @@ -161,23 +166,23 @@ public UserDelegationSasTestData setRequestQueryParameters(Map r return this; } - public UserDelegationSasTestData setSaoid(String saoid) { - this.saoid = saoid; + public UserDelegationSasTestData setPreauthorizedAgentObjectId(String preauthorizedAgentObjectId) { + this.preauthorizedAgentObjectId = preauthorizedAgentObjectId; return this; } - public UserDelegationSasTestData setSuoid(String suoid) { - this.suoid = suoid; + public UserDelegationSasTestData setAgentObjectId(String agentObjectId) { + this.agentObjectId = agentObjectId; return this; } - public UserDelegationSasTestData setCid(String cid) { - this.cid = cid; + public UserDelegationSasTestData setCorrelationId(String correlationId) { + this.correlationId = correlationId; return this; } - public UserDelegationSasTestData setDelegatedOid(String delegatedOid) { - this.delegatedOid = delegatedOid; + public UserDelegationSasTestData setDelegatedUserObjectId(String delegatedUserObjectId) { + this.delegatedUserObjectId = delegatedUserObjectId; return this; } @@ -190,8 +195,454 @@ public Arguments toArguments() { return Arguments.of( getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, getIpRange(), getProtocol(), getSnapshotId(), getCacheControl(), getDisposition(), getEncoding(), - getLanguage(), getType(), getVersionId(), saoid, cid, - getEncryptionScope(), delegatedOid, requestHeaders, requestQueryParameters, getExpectedStringToSign() + getLanguage(), getType(), getVersionId(), preauthorizedAgentObjectId, correlationId, + getEncryptionScope(), delegatedUserObjectId, requestHeaders, requestQueryParameters, getExpectedStringToSign() ); } + + public Arguments toDatalakeArguments() { + return Arguments.of( + getStartTime(), keyOid, keyTid, keyStart, keyExpiry, keyService, keyVersion, keyValue, + getIpRange(), getProtocol(), getCacheControl(), getDisposition(), getEncoding(), + getLanguage(), getType(), preauthorizedAgentObjectId, agentObjectId, correlationId, + requestHeaders, requestQueryParameters, getExpectedStringToSign() + ); + } + + /* + We test string to sign functionality directly related toUserDelegation sas specific parameters + */ + public static Stream blobSasImplUtilStringToSignUserDelegationKeySupplier() { + // Use LinkedHashMap to ensure deterministic iteration order + Map singleHeader = new LinkedHashMap<>(); + singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); + + Map singleQueryParam = new LinkedHashMap<>(); + singleQueryParam.put("comp", "blocklist"); + + Map multipleHeaders = new LinkedHashMap<>(); + multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); + multipleHeaders.put("x-ms-source-if-match", "etag"); + + Map multipleQueryParams = new LinkedHashMap<>(); + multipleQueryParams.put("blockid", "blockidvalue"); + multipleQueryParams.put("comp", "blocklist"); + + OffsetDateTime expiryTime = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + String expiryTimeStr = Constants.ISO_8601_UTC_DATE_FORMATTER.format(expiryTime); + + return Stream.of( + //StartTime + new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n" + + expiryTimeStr + + "\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Key Object ID + new UserDelegationSasTestData().setKeyOid("11111111-1111-1111-1111-111111111111") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Key Tenant ID + new UserDelegationSasTestData().setKeyTid("22222222-2222-2222-2222-222222222222") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Key Start Time + new UserDelegationSasTestData() + .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Key Expiry Time + new UserDelegationSasTestData() + .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Key Service + new UserDelegationSasTestData().setKeyService("b") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Key Version + new UserDelegationSasTestData().setKeyVersion("2018-06-17") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Sas Ip Range + new UserDelegationSasTestData().setIpRange(new SasIpRange().setIpMin("ip")) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Sas Protocol + new UserDelegationSasTestData().setProtocol(SasProtocol.HTTPS_ONLY) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n" + SasProtocol.HTTPS_ONLY + "\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Snapshot ID + new UserDelegationSasTestData().setSnapshotId("snapId") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbs\nsnapId\n\n\n\n\n\n\n\n") + .toArguments(), + // Cache Control + new UserDelegationSasTestData().setCacheControl("control") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\ncontrol\n\n\n\n") + .toArguments(), + // Content Disposition + new UserDelegationSasTestData().setDisposition("disposition") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\ndisposition\n\n\n") + .toArguments(), + // Content Encoding + new UserDelegationSasTestData().setEncoding("encoding") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\nencoding\n\n") + .toArguments(), + // Content Language + new UserDelegationSasTestData().setLanguage("language") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\nlanguage\n") + .toArguments(), + // Content Type + new UserDelegationSasTestData().setType("type") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\ntype") + .toArguments(), + // Version ID + new UserDelegationSasTestData().setVersionId("versionId") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nbv\nversionId\n\n\n\n\n\n\n\n") + .toArguments(), + // Saoid - Preauthorized Agent Object ID + new UserDelegationSasTestData().setPreauthorizedAgentObjectId("saoid") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Correlation ID + new UserDelegationSasTestData().setCorrelationId("cid") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Encryption Scope + new UserDelegationSasTestData().setEncryptionScope("encryptionScope") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\nencryptionScope\n\n\n\n\n\n\n") + .toArguments(), + // Delegated User Object ID + new UserDelegationSasTestData().setDelegatedUserObjectId("delegatedOid") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\ndelegatedOid\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toArguments(), + // Request Headers (single header) + new UserDelegationSasTestData().setRequestHeaders(singleHeader) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n") + .toArguments(), + // Request Query Params (single param) + new UserDelegationSasTestData().setRequestQueryParameters(singleQueryParam) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n") + .toArguments(), + // Request Headers and Query Params (single each) + new UserDelegationSasTestData().setRequestQueryParameters(singleQueryParam) + .setRequestHeaders(singleHeader) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n") + .toArguments(), + // Test multiple headers and multiple query parameters + new UserDelegationSasTestData().setRequestHeaders(multipleHeaders) + .setRequestQueryParameters(multipleQueryParams) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" + + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n") + .toArguments(), + // Test with all parameters populated + new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setKeyOid("11111111-1111-1111-1111-111111111111") + .setKeyTid("22222222-2222-2222-2222-222222222222") + .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 6, 1, 0, 0), ZoneOffset.UTC)) + .setKeyService("b") + .setKeyVersion("2018-06-17") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setIpRange(new SasIpRange().setIpMin("ip")) + .setProtocol(SasProtocol.HTTPS_ONLY) + .setSnapshotId("snapId") + .setCacheControl("control") + .setDisposition("disposition") + .setEncoding("encoding") + .setLanguage("language") + .setType("type") + .setVersionId(null) // versionId and snapId are mutually exclusive + .setPreauthorizedAgentObjectId("saoid") + .setCorrelationId("cid") + .setEncryptionScope("encryptionScope") + .setDelegatedUserObjectId("delegatedOid") + .setRequestHeaders(multipleHeaders) + .setRequestQueryParameters(multipleQueryParams) + .setExpectedStringToSign("r\n" // permissions + + expiryTimeStr // startTime + + "\n" + + expiryTimeStr // expiryTime + + "\n/blob/%s/containerName/blobName\n" // canonicalName + + "11111111-1111-1111-1111-111111111111\n" // keyOid + + "22222222-2222-2222-2222-222222222222\n" // keyTid + + "2018-01-01T00:00:00Z\n" // keyStart + + "2018-06-01T00:00:00Z\n" // keyExpiry + + "b\n" // keyService + + "2018-06-17\n" // keyVersion + + "saoid\n" // saoid (preauthorizedAgentObjectId) + + "\n" // suoid (always empty) + + "cid\n" // cid (correlationId) + + "\n" // delegatedUserTenantId (removed - empty) + + "delegatedOid\n" // delegatedUserObjectId + + "ip\n" // sasIpRange + + SasProtocol.HTTPS_ONLY + "\n" // protocol + + Constants.SAS_SERVICE_VERSION + "\n" // VERSION + + "bs\n" // resource (blob snapshot) + + "snapId\n" // snapId (versionSegment with snapId) + + "encryptionScope\n" // encryptionScope + + "x-ms-encryption-key-sha256:hashvalue\n" // requestHeaders (multiple) + + "x-ms-source-if-match:etag\n\n" // requestHeaders continuation + newline separator + + "\nblockid:blockidvalue\n" // requestQueryParameters (multiple, with prepended newline) + + "comp:blocklist\n" // requestQueryParameters continuation + + "control\n" // cacheControl + + "disposition\n" // contentDisposition + + "encoding\n" // contentEncoding + + "language\n" // contentLanguage + + "type" // contentType (no trailing newline) + ) + .toArguments()); + } + + public static Stream dataLakeSasImplUtilStringToSignUserDelegationKeySupplier() { + // Use LinkedHashMap to ensure deterministic iteration order + Map singleHeader = new LinkedHashMap<>(); + singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); + + Map singleQueryParam = new LinkedHashMap<>(); + singleQueryParam.put("comp", "blocklist"); + + Map multipleHeaders = new LinkedHashMap<>(); + multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); + multipleHeaders.put("x-ms-source-if-match", "etag"); + + Map multipleQueryParams = new LinkedHashMap<>(); + multipleQueryParams.put("blockid", "blockidvalue"); + multipleQueryParams.put("comp", "blocklist"); + + OffsetDateTime expiryTime = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); + String expiryTimeStr = Constants.ISO_8601_UTC_DATE_FORMATTER.format(expiryTime); + + // We test string to sign functionality directly related to user delegation sas specific parameters + return Stream.of( + // Start time + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n" + + expiryTimeStr + + "\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyOid("11111111-1111-1111-1111-111111111111") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyTid("22222222-2222-2222-2222-222222222222") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData() + .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData() + .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyService("b") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyVersion("2018-06-17") + .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setIpRange(new SasIpRange().setIpMin("ip")) + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setEncoding("encoding") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\nencoding\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setType("type") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\n\n\n\n\ntype") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setPreauthorizedAgentObjectId("saoid") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setAgentObjectId("suoid") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\nsuoid\n\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setCorrelationId("cid") + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" + + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestHeaders(singleHeader) + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestQueryParameters(singleQueryParam) + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestHeaders(singleHeader) + .setRequestQueryParameters(singleQueryParam) + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n") + .toDatalakeArguments(), + new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") + .setRequestHeaders(multipleHeaders) + .setRequestQueryParameters(multipleQueryParams) + .setExpectedStringToSign("r\n\n" + + expiryTimeStr + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" + + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n") + .toDatalakeArguments()); + } } diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java index f5b7fe8b78f9..eee896279a2f 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/sas/DataLakeServiceSasSignatureValues.java @@ -4,7 +4,6 @@ package com.azure.storage.file.datalake.sas; import com.azure.core.util.Configuration; -import com.azure.storage.blob.sas.BlobServiceSasSignatureValues; import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.implementation.StorageImplUtils; import com.azure.storage.common.sas.SasIpRange; diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 25a304e0deb6..4229b3250b9b 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -14,8 +14,6 @@ import com.azure.storage.common.sas.SasIpRange; import com.azure.storage.common.sas.SasProtocol; import com.azure.storage.common.test.shared.StorageCommonTestUtils; -import com.azure.storage.common.test.shared.SasTestData; -import com.azure.storage.common.test.shared.UserDelegationSasTestData; import com.azure.storage.common.test.shared.extensions.LiveOnly; import com.azure.storage.common.test.shared.extensions.RequiredServiceVersion; import com.azure.storage.file.datalake.implementation.util.DataLakeSasImplUtil; @@ -36,19 +34,15 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import java.io.ByteArrayOutputStream; -import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.Map; -import java.util.stream.Stream; import static com.azure.storage.common.test.shared.StorageCommonTestUtils.getOidFromToken; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; @@ -745,7 +739,7 @@ public void accountSasTokenOnEndpoint() { */ @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2020-12-06") @ParameterizedTest - @MethodSource("sasImplUtilStringToSignSupplier") + @MethodSource("com.azure.storage.common.test.shared.SasTestData#dataLakeSasImplUtilStringToSignSupplier") public void sasImplUtilStringToSign(OffsetDateTime startTime, String identifier, SasIpRange ipRange, SasProtocol protocol, String cacheControl, String disposition, String encoding, String language, String type, String expectedStringToSign) { @@ -775,60 +769,14 @@ public void sasImplUtilStringToSign(OffsetDateTime startTime, String identifier, assertEquals(expected, util.stringToSign(util.getCanonicalName(ENVIRONMENT.getDataLakeAccount().getName()))); } - private static Stream sasImplUtilStringToSignSupplier() { - // We don't test the blob or containerName properties because canonicalized resource is always added as at least - // /blob/accountName. We test canonicalization of resources later. Again, this is not to test a fully functional - // sas but the construction of the string to sign. - // Signed resource is tested elsewhere, as we work some minor magic in choosing which value to use. - OffsetDateTime expiryTime = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); - String expiryTimeStr = Constants.ISO_8601_UTC_DATE_FORMATTER.format(expiryTime); - - return Stream.of(new SasTestData().setStartTime(expiryTime) - .setExpectedStringToSign("r\n" + expiryTimeStr + "\n" + expiryTimeStr - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - .toArguments(), - new SasTestData().setIdentifier("id") - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\nid\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - .toArguments(), - new SasTestData().setIpRange(new SasIpRange()) - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\nip\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - .toArguments(), - new SasTestData().setProtocol(SasProtocol.HTTPS_ONLY) - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n" - + SasProtocol.HTTPS_ONLY + "\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n") - .toArguments(), - new SasTestData().setCacheControl("control") - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\ncontrol\n\n\n\n") - .toArguments(), - new SasTestData().setDisposition("disposition") - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\ndisposition\n\n\n") - .toArguments(), - new SasTestData().setEncoding("encoding") - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\nencoding\n\n") - .toArguments(), - new SasTestData().setLanguage("language") - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\nlanguage\n") - .toArguments(), - new SasTestData().setType("type") - .setExpectedStringToSign("r\n\n" + expiryTimeStr + "\n/blob/%s/fileSystemName/pathName\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\ntype") - .toArguments()); - } - @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2020-12-06") @ParameterizedTest - @MethodSource("sasImplUtilStringToSignUserDelegationKeySupplier") + @MethodSource("com.azure.storage.common.test.shared.UserDelegationSasTestData#dataLakeSasImplUtilStringToSignUserDelegationKeySupplier") public void sasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, String keyOid, String keyTid, OffsetDateTime keyStart, OffsetDateTime keyExpiry, String keyService, String keyVersion, String keyValue, SasIpRange ipRange, SasProtocol protocol, String cacheControl, String disposition, String encoding, - String language, String type, Map requestHeaders, Map requestQueryParameters, - String saoid, String suoid, String cid, String expectedStringToSign) { + String language, String type, String saoid, String suoid, String cid, Map requestHeaders, + Map requestQueryParameters, String expectedStringToSign) { OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); PathSasPermission p = new PathSasPermission().setReadPermission(true); @@ -848,11 +796,8 @@ public void sasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, S .setPreauthorizedAgentObjectId(saoid) .setAgentObjectId(suoid) .setRequestHeaders(requestHeaders) - .setRequestQueryParameters(requestQueryParameters); - - if (ipRange != null) { - v.setSasIpRange(new SasIpRange().setIpMin("ip")); - } + .setRequestQueryParameters(requestQueryParameters) + .setSasIpRange(ipRange); UserDelegationKey key = new UserDelegationKey().setSignedObjectId(keyOid) .setSignedTenantId(keyTid) @@ -864,186 +809,14 @@ public void sasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, S DataLakeSasImplUtil util = new DataLakeSasImplUtil(v, "fileSystemName", "pathName", false); util.ensureState(); - String sasToken = util.generateUserDelegationSas(key, ENVIRONMENT.getDataLakeAccount().getName(), - stringToSign::add, Context.NONE); + util.generateUserDelegationSas(key, ENVIRONMENT.getDataLakeAccount().getName(), stringToSign::add, + Context.NONE); assertEqualsForEachLine(stringToSign, expected); assertEquals(expected, util.stringToSign(key, util.getCanonicalName(ENVIRONMENT.getDataLakeAccount().getName()))); } - private static Stream sasImplUtilStringToSignUserDelegationKeySupplier() { - // Use LinkedHashMap to ensure deterministic iteration order - Map singleHeader = new LinkedHashMap<>(); - singleHeader.put("x-ms-encryption-key-sha256", "hashvalue"); - - Map singleQueryParam = new LinkedHashMap<>(); - singleQueryParam.put("comp", "blocklist"); - - Map multipleHeaders = new LinkedHashMap<>(); - multipleHeaders.put("x-ms-encryption-key-sha256", "hashvalue"); - multipleHeaders.put("x-ms-source-if-match", "etag"); - - Map multipleQueryParams = new LinkedHashMap<>(); - multipleQueryParams.put("blockid", "blockidvalue"); - multipleQueryParams.put("comp", "blocklist"); - - // We test string to sign functionality directly related to user delegation sas specific parameters - return Stream.of( - // Start time - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setStartTime(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyOid("11111111-1111-1111-1111-111111111111") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n11111111-1111-1111-1111-111111111111\n\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyTid("22222222-2222-2222-2222-222222222222") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n22222222-2222-2222-2222-222222222222\n\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData() - .setKeyStart(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData() - .setKeyExpiry(OffsetDateTime.of(LocalDateTime.of(2018, 1, 1, 0, 0), ZoneOffset.UTC)) - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n2018-01-01T00:00:00Z\n\n\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyService("b") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\nb\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyVersion("2018-06-17") - .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n2018-06-17\n\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setIpRange(new SasIpRange()) - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\nip\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setEncoding("encoding") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\nencoding\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setType("type") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\n\n\n\n\ntype") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setSaoid("saoid") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setSuoid("suoid") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\nsuoid\n\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setCid("cid") - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\ncid\n\n\n\n\n" - + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setRequestHeaders(singleHeader) - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setRequestQueryParameters(singleQueryParam) - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\n\n\ncomp:blocklist\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setRequestHeaders(singleHeader) - .setRequestQueryParameters(singleQueryParam) - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n\n\ncomp:blocklist\n\n\n\n\n") - .toArguments(), - new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setRequestHeaders(multipleHeaders) - .setRequestQueryParameters(multipleQueryParams) - .setExpectedStringToSign("r\n\n" - + Constants.ISO_8601_UTC_DATE_FORMATTER - .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION - + "\nb\n\n\nx-ms-encryption-key-sha256:hashvalue\n" - + "x-ms-source-if-match:etag\n\n\nblockid:blockidvalue\n" + "comp:blocklist\n\n\n\n\n") - .toArguments()); - } - @Test public void canUseSasToAuthenticate() { AccountSasService service = new AccountSasService().setBlobAccess(true); From c3db81bea359e03fc1f44126a9598c1ef2446a5a Mon Sep 17 00:00:00 2001 From: Isabelle Date: Tue, 3 Feb 2026 13:00:43 -0800 Subject: [PATCH 29/37] removing debugging method --- .../storage/blob/SasAsyncClientTests.java | 7 +++- .../azure/storage/blob/SasClientTests.java | 38 +------------------ .../azure/storage/file/datalake/SasTests.java | 33 +--------------- 3 files changed, 7 insertions(+), 71 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 613dff661a2b..c75b4f2e2807 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -54,6 +54,7 @@ import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; @@ -1070,6 +1071,7 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim Map requestQueryParameters, String expectedStringToSign) { OffsetDateTime e = OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); BlobSasPermission p = new BlobSasPermission().setReadPermission(true); + ArrayList stringToSign = new ArrayList<>(); BlobServiceSasSignatureValues v = new BlobServiceSasSignatureValues(e, p); String expected = String.format(expectedStringToSign, ENVIRONMENT.getPrimaryAccount().getName()); @@ -1098,11 +1100,12 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim BlobSasImplUtil implUtil = new BlobSasImplUtil(v, "containerName", "blobName", snapId, versionId, encryptionScope); - String sasToken - = implUtil.generateUserDelegationSas(key, ENVIRONMENT.getPrimaryAccount().getName(), Context.NONE); + String sasToken = implUtil.generateUserDelegationSas(key, ENVIRONMENT.getPrimaryAccount().getName(), + stringToSign::add, Context.NONE); CommonSasQueryParameters token = BlobUrlParts.parse(ccAsync.getBlobContainerUrl() + "?" + sasToken).getCommonSasQueryParameters(); + assertEquals(expected, stringToSign.get(0), "String-to-sign mismatch"); assertEquals(token.getSignature(), StorageImplUtils.computeHMac256(key.getValue(), expected)); } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 8e5f68cf61b1..51d711d64296 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -1014,7 +1014,7 @@ public void blobSasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTim CommonSasQueryParameters token = BlobUrlParts.parse(cc.getBlobContainerUrl() + "?" + sasToken).getCommonSasQueryParameters(); - assertEqualsForEachLine(stringToSign, expected); + assertEquals(expected, stringToSign.get(0), "String-to-sign mismatch"); assertEquals(token.getSignature(), StorageImplUtils.computeHMac256(key.getValue(), expected)); } @@ -1103,40 +1103,4 @@ private static Stream accountSasImplUtilStringToSignSupplier() { .format(OffsetDateTime.of(2017, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)) + "\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nencryptionScope\n")); } - - private static void assertEqualsForEachLine(ArrayList stringToSign, String expected) { - String actual = stringToSign.get(0); - if (!expected.equals(actual)) { - StringBuilder output = new StringBuilder(); - String[] expectedLines = expected.split("\n", -1); - String[] actualLines = actual.split("\n", -1); - - output.append("\n=== Line-by-Line String-to-Sign Comparison ===\n"); - output.append("Expected lines: ").append(expectedLines.length).append("\n"); - output.append("Actual lines: ").append(actualLines.length).append("\n\n"); - - int maxLines = Math.max(expectedLines.length, actualLines.length); - for (int i = 0; i < maxLines; i++) { - String expLine = i < expectedLines.length ? expectedLines[i] : ""; - String actLine = i < actualLines.length ? actualLines[i] : ""; - - if (!expLine.equals(actLine)) { - output.append("Line ").append(i).append(" differs:\n"); - output.append(" Expected: [").append(expLine).append("]\n"); - output.append(" Actual: [").append(actLine).append("]\n\n"); - } else { - output.append("Line ").append(i).append(" matches: [").append(expLine).append("]\n"); - } - } - - output.append("=== Full Expected String ===\n"); - output.append(expected.replace("\n", "\\n\n")); - output.append("\n\n=== Full Actual String ===\n"); - output.append(actual.replace("\n", "\\n\n")); - - // Print everything at once - System.out.println(output); - } - assertEquals(expected, actual, "String-to-sign mismatch"); - } } diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 4229b3250b9b..d73b934ee719 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -812,7 +812,7 @@ public void sasImplUtilStringToSignUserDelegationKey(OffsetDateTime startTime, S util.generateUserDelegationSas(key, ENVIRONMENT.getDataLakeAccount().getName(), stringToSign::add, Context.NONE); - assertEqualsForEachLine(stringToSign, expected); + assertEquals(expected, stringToSign.get(0), "String-to-sign mismatch"); assertEquals(expected, util.stringToSign(key, util.getCanonicalName(ENVIRONMENT.getDataLakeAccount().getName()))); } @@ -884,35 +884,4 @@ public void canUseSasToAuthenticate() { .getProperties()); } - private static void assertEqualsForEachLine(ArrayList stringToSign, String expected) { - String actual = stringToSign.get(0); - if (!expected.equals(actual)) { - StringBuilder output = new StringBuilder(); - String[] expectedLines = expected.split("\n", -1); - String[] actualLines = actual.split("\n", -1); - - output.append("\n=== Line-by-Line String-to-Sign Comparison ===\n"); - output.append("Expected lines: ").append(expectedLines.length).append("\n"); - output.append("Actual lines: ").append(actualLines.length).append("\n\n"); - - int maxLines = Math.max(expectedLines.length, actualLines.length); - for (int i = 0; i < maxLines; i++) { - String expLine = i < expectedLines.length ? expectedLines[i] : ""; - String actLine = i < actualLines.length ? actualLines[i] : ""; - - if (!expLine.equals(actLine)) { - output.append("Line ").append(i).append(" differs:\n"); - output.append(" Expected: [").append(expLine).append("]\n"); - output.append(" Actual: [").append(actLine).append("]\n\n"); - } else { - output.append("Line ").append(i).append(" matches: [").append(expLine).append("]\n"); - } - } - - // Print everything at once - System.out.println(output.toString()); - } - assertEquals(expected, actual, "String-to-sign mismatch"); - } - } From 8421a1775ae339b354eda3cbe30ac88ddf184c4e Mon Sep 17 00:00:00 2001 From: Isabelle Date: Wed, 4 Feb 2026 09:05:51 -0800 Subject: [PATCH 30/37] updating assets and fixing spelling --- sdk/storage/azure-storage-blob/assets.json | 2 +- .../shared/UserDelegationSasTestData.java | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index f9a5c195881a..a061cfdadf8e 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_6631ad464e" + "Tag": "java/storage/azure-storage-blob_caf07f54e8" } diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java index 97702d1373cf..a0b6b7dbe741 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java @@ -364,12 +364,12 @@ public static Stream blobSasImplUtilStringToSignUserDelegationKeySupp + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nbv\nversionId\n\n\n\n\n\n\n\n") .toArguments(), - // Saoid - Preauthorized Agent Object ID - new UserDelegationSasTestData().setPreauthorizedAgentObjectId("saoid") + // Preauthorized Agent Object ID + new UserDelegationSasTestData().setPreauthorizedAgentObjectId("preAuthAgentOid") .setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") .setExpectedStringToSign("r\n\n" + expiryTimeStr - + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + + "\n/blob/%s/containerName/blobName\n\n\n\n\n\n\npreAuthAgentOid\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") .toArguments(), // Correlation ID @@ -449,7 +449,7 @@ public static Stream blobSasImplUtilStringToSignUserDelegationKeySupp .setLanguage("language") .setType("type") .setVersionId(null) // versionId and snapId are mutually exclusive - .setPreauthorizedAgentObjectId("saoid") + .setPreauthorizedAgentObjectId("preAuthAgentOid") .setCorrelationId("cid") .setEncryptionScope("encryptionScope") .setDelegatedUserObjectId("delegatedOid") @@ -466,8 +466,8 @@ public static Stream blobSasImplUtilStringToSignUserDelegationKeySupp + "2018-06-01T00:00:00Z\n" // keyExpiry + "b\n" // keyService + "2018-06-17\n" // keyVersion - + "saoid\n" // saoid (preauthorizedAgentObjectId) - + "\n" // suoid (always empty) + + "preAuthAgentOid\n" // preauthorizedAgentObjectId + + "\n" // (always empty for blob, agentObjectId) + "cid\n" // cid (correlationId) + "\n" // delegatedUserTenantId (removed - empty) + "delegatedOid\n" // delegatedUserObjectId @@ -593,17 +593,17 @@ public static Stream dataLakeSasImplUtilStringToSignUserDelegationKey + "\nb\n\n\n\n\n\n\n\n\ntype") .toDatalakeArguments(), new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setPreauthorizedAgentObjectId("saoid") + .setPreauthorizedAgentObjectId("preAuthAgentOid") .setExpectedStringToSign("r\n\n" + expiryTimeStr - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\nsaoid\n\n\n\n\n\n\n" + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\npreAuthAgentOid\n\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") .toDatalakeArguments(), new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") - .setAgentObjectId("suoid") + .setAgentObjectId("agentOid") .setExpectedStringToSign("r\n\n" + expiryTimeStr - + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\nsuoid\n\n\n\n\n\n" + + "\n/blob/%s/fileSystemName/pathName\n\n\n\n\n\n\n\nagentOid\n\n\n\n\n\n" + Constants.SAS_SERVICE_VERSION + "\nb\n\n\n\n\n\n\n\n\n") .toDatalakeArguments(), new UserDelegationSasTestData().setKeyValue("3hd4LRwrARVGbeMRQRfTLIsGMkCPuZJnvxZDU7Gak8c=") From 9e8e86c5747d99b88e84e561dcfb51b07f7819e9 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Wed, 4 Feb 2026 14:17:34 -0800 Subject: [PATCH 31/37] removing unused import --- .../test/java/com/azure/storage/blob/SasAsyncClientTests.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index c75b4f2e2807..1f39096c3f5a 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -51,7 +51,6 @@ import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; -import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; From 172bfbec0c4499b897dd0d69d666a2730fe37f8e Mon Sep 17 00:00:00 2001 From: Isabelle Date: Thu, 5 Feb 2026 17:03:59 -0800 Subject: [PATCH 32/37] bruh --- .../implementation/util/BlobSasImplUtil.java | 16 ++-- .../com/azure/storage/blob/BlobTestBase.java | 24 ++++++ .../storage/blob/SasAsyncClientTests.java | 52 +++++++++++++ .../azure/storage/blob/SasClientTests.java | 48 +++++++++++- .../common/implementation/SasImplUtils.java | 74 +++++++++++++------ .../common/sas/CommonSasQueryParameters.java | 26 ++++--- .../implementation/SasImplUtilsTests.java | 70 ++++++++++++++---- .../util/DataLakeSasImplUtil.java | 14 ++-- 8 files changed, 256 insertions(+), 68 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java index a24f2ab762bf..106e2216fa70 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java @@ -25,8 +25,8 @@ import java.util.function.Consumer; import static com.azure.storage.common.implementation.SasImplUtils.formatQueryParameterDate; -import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeadersForSasSigning; -import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParametersForSasSigning; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeaders; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParameters; import static com.azure.storage.common.implementation.SasImplUtils.tryAppendQueryParameter; /** @@ -202,7 +202,7 @@ public String generateUserDelegationSas(UserDelegationKey delegationKey, String // Signature is generated on the un-url-encoded values. final String canonicalName = getCanonicalName(accountName); - final String stringToSign = stringToSign(delegationKey, canonicalName); + final String stringToSign = stringToSign(delegationKey, canonicalName, true); StorageImplUtils.logStringToSign(LOGGER, stringToSign, context); String signature = StorageImplUtils.computeHMac256(delegationKey.getValue(), stringToSign); @@ -260,9 +260,9 @@ private String encode(UserDelegationKey userDelegationKey, String signature) { tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNATURE, signature); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_ENCRYPTION_SCOPE, this.encryptionScope); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_HEADERS, - formatRequestHeadersForSasSigning(this.requestHeaders)); + formatRequestHeaders(this.requestHeaders, false)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, - formatRequestQueryParametersForSasSigning(this.requestQueryParameters)); + formatRequestQueryParameters(this.requestQueryParameters, false)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_ENCODING, this.contentEncoding); @@ -367,7 +367,7 @@ private String stringToSign(String canonicalName) { } } - private String stringToSign(final UserDelegationKey key, String canonicalName) { + private String stringToSign(final UserDelegationKey key, String canonicalName, Boolean includeValuesInPairs) { String versionSegment = this.snapshotId == null ? this.versionId : this.snapshotId; if (VERSION.compareTo(BlobServiceVersion.V2019_12_12.getVersion()) <= 0) { return String.join("\n", this.permissions == null ? "" : this.permissions, @@ -476,10 +476,10 @@ private String stringToSign(final UserDelegationKey key, String canonicalName) { this.sasIpRange == null ? "" : this.sasIpRange.toString(), this.protocol == null ? "" : this.protocol.toString(), VERSION, resource, versionSegment == null ? "" : versionSegment, this.encryptionScope == null ? "" : this.encryptionScope, - this.requestHeaders == null ? "" : formatRequestHeadersForSasSigning(this.requestHeaders), + this.requestHeaders == null ? "" : formatRequestHeaders(this.requestHeaders, includeValuesInPairs), this.requestQueryParameters == null ? "" - : formatRequestQueryParametersForSasSigning(this.requestQueryParameters), + : formatRequestQueryParameters(this.requestQueryParameters, includeValuesInPairs), this.cacheControl == null ? "" : this.cacheControl, this.contentDisposition == null ? "" : this.contentDisposition, this.contentEncoding == null ? "" : this.contentEncoding, diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java index 3c0db26ebfd4..b32ff69531f2 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobTestBase.java @@ -57,6 +57,7 @@ import com.azure.storage.blob.specialized.BlobLeaseClientBuilder; import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder; import com.azure.storage.common.StorageSharedKeyCredential; +import com.azure.storage.common.Utility; import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.policy.RequestRetryOptions; import com.azure.storage.common.test.shared.StorageCommonTestUtils; @@ -86,6 +87,7 @@ import java.util.Base64; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Queue; import java.util.concurrent.Callable; @@ -1288,4 +1290,26 @@ protected static void validatePropsSet(BlobServiceProperties sent, BlobServicePr received.getStaticWebsite().getErrorDocument404Path()); } } + + public static HttpPipelinePolicy getAddHeadersAndQueryPolicy(Map requestHeaders, + Map requestQueryParams) { + // Create policy to add headers and query params to request + return (context, next) -> { + // Add request headers + for (Map.Entry entry : requestHeaders.entrySet()) { + context.getHttpRequest().setHeader(HttpHeaderName.fromString(entry.getKey()), entry.getValue()); + } + + // Add query parameters + String extraQuery = requestQueryParams.entrySet() + .stream() + .map(e -> Utility.urlEncode(e.getKey()) + "=" + Utility.urlEncode(e.getValue())) + .collect(Collectors.joining("&")); + + String currentUrl = context.getHttpRequest().getUrl().toString(); + context.getHttpRequest().setUrl(currentUrl + "&" + extraQuery); + + return next.process(); + }; + } } diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 883e9197ec9a..26ee6bbebf40 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -989,6 +989,58 @@ public void canUseSasToAuthenticate() { StepVerifier.create(serviceClient.getProperties()).expectNextCount(1).verifyComplete(); } + // RBAC replication lag + @Test + @LiveOnly + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-02-06") + public void blobDynamicUserDelegationSas() { + liveTestScenarioWithRetry(() -> { + // Create container and blob using OAuth service client + BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); + BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(cc.getBlobContainerName()); + BlobAsyncClient oauthBlob = oauthContainer.getBlobAsyncClient(blobName); + + // Define request headers and query parameters + Map requestHeaders = new HashMap<>(); + requestHeaders.put("foo$", "bar!"); + requestHeaders.put("company", "msft"); + requestHeaders.put("city", "redmond,atlanta,reston"); + + Map requestQueryParams = new HashMap<>(); + requestQueryParams.put("hello$", "world!"); + requestQueryParams.put("check", "spelling"); + requestQueryParams.put("firstName", "john,Tim"); + + // Generate user delegation SAS with request headers and query params + BlobSasPermission permissions = new BlobSasPermission().setReadPermission(true).setDeletePermission(true); + OffsetDateTime expiryTime = testResourceNamer.now().plusHours(1); + + BlobServiceSasSignatureValues sasValues + = new BlobServiceSasSignatureValues(expiryTime, permissions).setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParams); + + Mono response = oauthService.getUserDelegationKey(null, expiryTime).flatMap(r -> { + String keyOid = testResourceNamer.recordValueFromConfig(r.getSignedObjectId()); + r.setSignedObjectId(keyOid); + + String keyTid = testResourceNamer.recordValueFromConfig(r.getSignedTenantId()); + r.setSignedTenantId(keyTid); + + String blobToken = ccAsync.generateUserDelegationSas(sasValues, r); + + // Create blob client with SAS token and custom policy + BlobAsyncClient identityBlob = new BlobClientBuilder().endpoint(oauthBlob.getBlobUrl()) + .sasToken(blobToken) + .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) + .buildAsyncClient(); + + return identityBlob.getProperties(); + }); + + StepVerifier.create(response).expectNextCount(1).verifyComplete(); + }); + } + private BlobServiceSasSignatureValues generateValues(BlobSasPermission permission) { return new BlobServiceSasSignatureValues(testResourceNamer.now().plusDays(1), permission) .setStartTime(testResourceNamer.now().minusDays(1)) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 1f0216d8ab35..8963cdc1ec4e 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -40,9 +40,6 @@ import org.junit.jupiter.params.provider.ValueSource; import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; @@ -905,6 +902,51 @@ public void canUseSasToAuthenticate() { .getProperties()); } + // RBAC replication lag + @Test + @LiveOnly + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-02-06") + public void blobDynamicUserDelegationSas() { + liveTestScenarioWithRetry(() -> { + // Create container and blob using OAuth service client + BlobServiceClient oauthService = getOAuthServiceClient(); + BlobContainerClient oauthContainer = oauthService.getBlobContainerClient(cc.getBlobContainerName()); + BlobClient oauthBlob = oauthContainer.getBlobClient(blobName); + + UserDelegationKey userDelegationKey = getUserDelegationInfo(); + + // Define request headers and query parameters + Map requestHeaders = new HashMap<>(); + requestHeaders.put("foo$", "bar!"); + requestHeaders.put("company", "msft"); + requestHeaders.put("city", "redmond,atlanta,reston"); + + Map requestQueryParams = new HashMap<>(); + requestQueryParams.put("hello$", "world!"); + requestQueryParams.put("check", "spelling"); + requestQueryParams.put("firstName", "john,Tim"); + + // Generate user delegation SAS with request headers and query params + BlobSasPermission permissions = new BlobSasPermission().setReadPermission(true).setDeletePermission(true); + OffsetDateTime expiryTime = testResourceNamer.now().plusHours(1); + + BlobServiceSasSignatureValues sasValues + = new BlobServiceSasSignatureValues(expiryTime, permissions).setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParams); + + String blobToken = oauthBlob.generateUserDelegationSas(sasValues, userDelegationKey); + + // Create blob client with SAS token and custom policy + BlobClient identityBlob = new BlobClientBuilder().endpoint(oauthBlob.getBlobUrl()) + .sasToken(blobToken) + .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) + .buildClient(); + + // Verify we can get blob properties + assertDoesNotThrow(identityBlob::getProperties); + }); + } + private BlobServiceSasSignatureValues generateValues(BlobSasPermission permission) { return new BlobServiceSasSignatureValues(testResourceNamer.now().plusDays(1), permission) .setStartTime(testResourceNamer.now().minusDays(1)) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java index 3708c442496c..4793b65cd443 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java @@ -9,15 +9,16 @@ import com.azure.storage.common.Utility; import com.azure.storage.common.policy.StorageSharedKeyCredentialPolicy; +import java.util.ArrayList; import java.util.Comparator; -import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TreeMap; /** * This class provides helper methods for sas. - * + *

* RESERVED FOR INTERNAL USE. */ public class SasImplUtils { @@ -123,53 +124,82 @@ public static Map parseQueryString(String queryParams) { * Formats request headers for SAS signing. * * @param requestHeaders The map of request headers to format. - * @return A formatted string with headers in the format "key:value" separated by newlines, or empty string if - * null/empty. Terminates each pair with a newline (\n). + * @param includeKeyValues Whether to include the values of the query parameters in the formatted string. + * If false, only the keys will be included, separated by commas. + * @return A formatted string with or without values depending on the includeKeyValues parameter. * @see * * Version 2026-04-06 and later (Blob Storage and Data Lake Storage) */ - public static String formatRequestHeadersForSasSigning(Map requestHeaders) { + public static String formatRequestHeaders(Map requestHeaders, Boolean includeKeyValues) { if (requestHeaders == null || requestHeaders.isEmpty()) { return null; } - StringBuilder sb = new StringBuilder(); - requestHeaders.forEach((key, value) -> sb.append(key).append(":").append(value).append("\n")); - return sb.toString(); + if (includeKeyValues) { + StringBuilder sb = new StringBuilder(); + requestHeaders.forEach((key, value) -> sb.append(key).append(":").append(value).append("\n")); + return sb.toString(); + } + return String.join(",", requestHeaders.keySet()); + } /** * Formats request headers for SAS signing. * * @param requestQueryParameters The map of request headers to format. - * @return A formatted string with query params in the format "key:value" separated by newlines, or empty string if - * null/empty. Prepends a newline character. Prefixes each pair with a newline (\n). + * @param includeKeyValues Whether to include the values of the query parameters in the formatted string. + * If false, only the keys will be included, separated by commas. + * @return A formatted string with or without values depending on the includeKeyValues parameter. * @see * * Version 2026-04-06 and later (Blob Storage and Data Lake Storage) */ - public static String formatRequestQueryParametersForSasSigning(Map requestQueryParameters) { + public static String formatRequestQueryParameters(Map requestQueryParameters, + Boolean includeKeyValues) { if (requestQueryParameters == null || requestQueryParameters.isEmpty()) { return null; } - StringBuilder sb = new StringBuilder(); - requestQueryParameters.forEach((key, value) -> sb.append("\n").append(key).append(":").append(value)); - return sb.toString(); + if (includeKeyValues) { + StringBuilder sb = new StringBuilder(); + requestQueryParameters.forEach((key, value) -> sb.append("\n").append(key).append(":").append(value)); + return sb.toString(); + } + return String.join(",", requestQueryParameters.keySet()); + } + + + /** + * Formats a list of keys into a comma separated string. + * + * @param listOfKeys The list of keys to format. + * @return A comma separated string of the keys, or null if the list is null/empty. + */ + public static String formatKeyList(List listOfKeys) { + if (listOfKeys == null || listOfKeys.isEmpty()) { + return null; + } + return String.join(",", listOfKeys); } - public static Map parseRequestHeadersAndQueryParameterString(String rawString) { + /** + * Parses a comma separated string of keys into a list. The values for the keys are never present at this point. + * + * @param rawString The comma separated string of keys to parse. + * @return A list of the keys, or null if the string is null/empty. + */ + public static List parseRequestHeadersAndQueryParameterString(String rawString) { if (CoreUtils.isNullOrEmpty(rawString)) { return null; } - Map valueMap = new HashMap<>(); - String[] pairs = rawString.split("\n"); - for (String pair : pairs) { - if (!CoreUtils.isNullOrEmpty(pair)) { - String[] keyValue = pair.split(":", 2); - valueMap.put(keyValue[0].trim(), keyValue[1].trim()); + String[] keys = rawString.split(","); + List keyList = new ArrayList<>(); + for (String key : keys) { + if (!CoreUtils.isNullOrEmpty(key)) { + keyList.add(key.trim()); } } - return valueMap; + return keyList; } } diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java index 53beaa44fe9b..02260b1ec0b4 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/sas/CommonSasQueryParameters.java @@ -9,11 +9,11 @@ import com.azure.storage.common.implementation.TimeAndFormat; import java.time.OffsetDateTime; +import java.util.List; import java.util.Map; import java.util.function.Function; -import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeadersForSasSigning; -import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParametersForSasSigning; +import static com.azure.storage.common.implementation.SasImplUtils.formatKeyList; /** * Represents the components that make up an Azure Storage SAS' query parameters. This type is not constructed directly @@ -49,8 +49,8 @@ public class CommonSasQueryParameters { private final String correlationId; private final String encryptionScope; private final String delegatedUserObjectId; - private final Map requestHeaders; - private final Map requestQueryParameters; + private final List requestHeaders; + private final List requestQueryParameters; /** * Creates a new {@link CommonSasQueryParameters} object. @@ -200,9 +200,9 @@ public String encode() { SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_KEY_VERSION, this.keyVersion); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNED_RESOURCE, this.resource); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_HEADERS, - formatRequestHeadersForSasSigning(this.requestHeaders)); + formatKeyList(this.requestHeaders)); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, - formatRequestQueryParametersForSasSigning(this.requestQueryParameters)); + formatKeyList(this.requestQueryParameters)); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); SasImplUtils.tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); @@ -499,25 +499,27 @@ public String getDelegatedUserObjectId() { /** * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Headers to include in the SAS. - * Any usage of the SAS must include these headers and values in the request. + * Any usage of the SAS must include these headers and values in the request. Only the header keys will be included + * in this list. * *

Note: This parameter is only valid for user delegation SAS.

* - * @return A map of request headers. + * @return A list of request headers. */ - public Map getRequestHeaders() { + public List getRequestHeaders() { return requestHeaders; } /** * Optional. Beginning in version 2026-04-06, this value specifies Custom Request Query Parameters to include in - * the SAS. Any usage of the SAS must include these query parameters and values in the request. + * the SAS. Any usage of the SAS must include these query parameters and values in the request. Only the query + * parameter keys will be included in this list. * *

Note: This parameter is only valid for user delegation SAS.

* - * @return A map of request query parameters. + * @return A list of request query parameters. */ - public Map getRequestQueryParameters() { + public List getRequestQueryParameters() { return requestQueryParameters; } } diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index 45f338ddfbff..2b2fae0fb4a6 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -26,26 +26,26 @@ public void setup() { } @Test - public void formatRequestHeadersForSasSigningNullReturnsNull() { - assertNull(SasImplUtils.formatRequestHeadersForSasSigning(null)); + public void formatRequestHeadersNullReturnsNull() { + assertNull(SasImplUtils.formatRequestHeaders(null, null)); } @Test - public void formatRequestHeadersForSasSigningEmptyReturnsNull() { - assertNull(SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders)); + public void formatRequestHeadersEmptyReturnsNull() { + assertNull(SasImplUtils.formatRequestHeaders(requestHeaders, null)); } @Test - public void formatRequestHeadersForSasSigningReturnsWithLastCharAsNewline() { + public void formatRequestHeadersReturnsWithLastCharAsNewline() { requestHeaders.put("Some-Header", "someValue"); - String headerString = SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders); + String headerString = SasImplUtils.formatRequestHeaders(requestHeaders, true); assertNotEquals("", headerString); assertEquals("\n", headerString.substring(headerString.length() - 1)); } @Test - public void formatRequestHeadersForSasSigningPopulatedHeaders() { + public void formatRequestHeadersForStringToSign() { requestHeaders.put(Constants.HeaderConstants.ENCRYPTION_KEY, "encryptionKeyValue"); requestHeaders.put(Constants.HeaderConstants.CONTENT_ENCODING, "contentEncodingValue"); requestHeaders.put(Constants.HeaderConstants.CONTENT_TYPE, "contentTypeValue"); @@ -55,7 +55,7 @@ public void formatRequestHeadersForSasSigningPopulatedHeaders() { = String.join("\n", "x-ms-encryption-key:encryptionKeyValue", "Content-Encoding:contentEncodingValue", "Content-Type:contentTypeValue", "x-ms-client-request-id:clientRequestId"); - String headers = SasImplUtils.formatRequestHeadersForSasSigning(requestHeaders); + String headers = SasImplUtils.formatRequestHeaders(requestHeaders, true); Integer newLineCount = Arrays.stream(headers.split("")).filter(s -> s.equals("\n")).collect(Collectors.toList()).size(); @@ -68,33 +68,54 @@ public void formatRequestHeadersForSasSigningPopulatedHeaders() { } @Test - public void formatRequestQueryParamsForSasSigningNullReturnsNull() { - assertNull(SasImplUtils.formatRequestQueryParametersForSasSigning(null)); + public void formatRequestHeaders() { + requestHeaders.put(Constants.HeaderConstants.ENCRYPTION_KEY, "encryptionKeyValue"); + requestHeaders.put(Constants.HeaderConstants.CONTENT_ENCODING, "contentEncodingValue"); + requestHeaders.put(Constants.HeaderConstants.CONTENT_TYPE, "contentTypeValue"); + requestHeaders.put(Constants.HeaderConstants.CLIENT_REQUEST_ID, "clientRequestId"); + + String expected + = String.join(",", "x-ms-encryption-key", "Content-Encoding", "Content-Type", "x-ms-client-request-id"); + + String headers = SasImplUtils.formatRequestHeaders(requestHeaders, false); + Integer expectedCount + = Arrays.stream(headers.split("")).filter(s -> s.equals(",")).collect(Collectors.toList()).size() + 1; + + String sortedExpected = Arrays.stream(expected.split(",")).sorted().collect(Collectors.joining(",")); + String sortedHeaders = Arrays.stream(headers.split(",")).sorted().collect(Collectors.joining(",")); + + assertEquals(4, expectedCount); + assertEquals(sortedExpected, sortedHeaders); + } + + @Test + public void formatRequestQueryParamsNullReturnsNull() { + assertNull(SasImplUtils.formatRequestQueryParameters(null, null)); } @Test - public void formatRequestQueryParamsForSasSigningEmptyReturnsNull() { - assertNull(SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams)); + public void formatRequestQueryParamsEmptyReturnsNull() { + assertNull(SasImplUtils.formatRequestQueryParameters(requestQueryParams, null)); } @Test - public void formatRequestQueryParamsForSasSigningReturnsWithFirstCharAsNewline() { + public void formatRequestQueryParamsReturnsWithFirstCharAsNewline() { requestQueryParams.put("someParam", "someValue"); - String queryParamString = SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams); + String queryParamString = SasImplUtils.formatRequestQueryParameters(requestQueryParams, true); assertNotEquals("", queryParamString); assertEquals("\n", queryParamString.substring(0, 1)); } @Test - public void formatRequestQueryParamsForSasSigningPopulatedParams() { + public void formatRequestQueryParamsForStringToSign() { requestQueryParams.put("paramA", "valueA"); requestQueryParams.put("paramB", "valueB"); requestQueryParams.put("paramC", "valueC"); String expected = "\nparamA:valueA\nparamB:valueB\nparamC:valueC"; - String queryParams = SasImplUtils.formatRequestQueryParametersForSasSigning(requestQueryParams); + String queryParams = SasImplUtils.formatRequestQueryParameters(requestQueryParams, true); Integer newLineCount = Arrays.stream(queryParams.split("")).filter(s -> s.equals("\n")).collect(Collectors.toList()).size(); String sortedExpected @@ -105,4 +126,21 @@ public void formatRequestQueryParamsForSasSigningPopulatedParams() { assertEquals(3, newLineCount); assertEquals(sortedExpected, sortedQueryParams); } + + @Test + public void formatRequestQueryParams() { + requestQueryParams.put("paramA", "valueA"); + requestQueryParams.put("paramB", "valueB"); + requestQueryParams.put("paramC", "valueC"); + String expected = "paramA,paramB,paramC"; + + String queryParams = SasImplUtils.formatRequestQueryParameters(requestQueryParams, false); + Integer expectedCount + = Arrays.stream(queryParams.split("")).filter(s -> s.equals(",")).collect(Collectors.toList()).size() + 1; + String sortedExpected = Arrays.stream(expected.split(",")).sorted().collect(Collectors.joining(",")); + String sortedHeaders = Arrays.stream(queryParams.split(",")).sorted().collect(Collectors.joining(",")); + + assertEquals(3, expectedCount); + assertEquals(sortedExpected, sortedHeaders); + } } diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java index 985080402296..6047743a2103 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java @@ -25,13 +25,13 @@ import java.util.function.Consumer; import static com.azure.storage.common.implementation.SasImplUtils.formatQueryParameterDate; -import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeadersForSasSigning; -import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParametersForSasSigning; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestHeaders; +import static com.azure.storage.common.implementation.SasImplUtils.formatRequestQueryParameters; import static com.azure.storage.common.implementation.SasImplUtils.tryAppendQueryParameter; /** * This class provides helper methods for common datalake service sas patterns. - * + *

* RESERVED FOR INTERNAL USE. */ public class DataLakeSasImplUtil { @@ -259,9 +259,9 @@ private String encode(UserDelegationKey userDelegationKey, String signature) { tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNATURE, signature); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_ENCRYPTION_SCOPE, this.encryptionScope); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_HEADERS, - formatRequestHeadersForSasSigning(this.requestHeaders)); + formatRequestHeaders(this.requestHeaders, true)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, - formatRequestQueryParametersForSasSigning(this.requestQueryParameters)); + formatRequestQueryParameters(this.requestQueryParameters, true)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_ENCODING, this.contentEncoding); @@ -478,10 +478,10 @@ public String stringToSign(final UserDelegationKey key, String canonicalName) { this.sasIpRange == null ? "" : this.sasIpRange.toString(), this.protocol == null ? "" : this.protocol.toString(), VERSION, resource, "", /* Version segment. */ this.encryptionScope == null ? "" : this.encryptionScope, - this.requestHeaders == null ? "" : formatRequestHeadersForSasSigning(this.requestHeaders), + this.requestHeaders == null ? "" : formatRequestHeaders(this.requestHeaders, true), this.requestQueryParameters == null ? "" - : formatRequestQueryParametersForSasSigning(this.requestQueryParameters), + : formatRequestQueryParameters(this.requestQueryParameters, true), this.cacheControl == null ? "" : this.cacheControl, this.contentDisposition == null ? "" : this.contentDisposition, this.contentEncoding == null ? "" : this.contentEncoding, From b1c9ad26a23aea6b1d1b6ee4f52f0c219acd0db1 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Fri, 6 Feb 2026 11:57:19 -0800 Subject: [PATCH 33/37] datalake tests --- .../implementation/util/BlobSasImplUtil.java | 8 +- .../storage/blob/SasAsyncClientTests.java | 5 +- .../common/implementation/SasImplUtils.java | 1 - .../util/DataLakeSasImplUtil.java | 4 +- .../file/datalake/DataLakeTestBase.java | 24 +++++ .../storage/file/datalake/SasAsyncTests.java | 91 +++++++++++++++++++ .../azure/storage/file/datalake/SasTests.java | 81 +++++++++++++++++ 7 files changed, 205 insertions(+), 9 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java index 106e2216fa70..cd45f7a31b6c 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/util/BlobSasImplUtil.java @@ -202,7 +202,7 @@ public String generateUserDelegationSas(UserDelegationKey delegationKey, String // Signature is generated on the un-url-encoded values. final String canonicalName = getCanonicalName(accountName); - final String stringToSign = stringToSign(delegationKey, canonicalName, true); + final String stringToSign = stringToSign(delegationKey, canonicalName); StorageImplUtils.logStringToSign(LOGGER, stringToSign, context); String signature = StorageImplUtils.computeHMac256(delegationKey.getValue(), stringToSign); @@ -367,7 +367,7 @@ private String stringToSign(String canonicalName) { } } - private String stringToSign(final UserDelegationKey key, String canonicalName, Boolean includeValuesInPairs) { + private String stringToSign(final UserDelegationKey key, String canonicalName) { String versionSegment = this.snapshotId == null ? this.versionId : this.snapshotId; if (VERSION.compareTo(BlobServiceVersion.V2019_12_12.getVersion()) <= 0) { return String.join("\n", this.permissions == null ? "" : this.permissions, @@ -476,10 +476,10 @@ private String stringToSign(final UserDelegationKey key, String canonicalName, B this.sasIpRange == null ? "" : this.sasIpRange.toString(), this.protocol == null ? "" : this.protocol.toString(), VERSION, resource, versionSegment == null ? "" : versionSegment, this.encryptionScope == null ? "" : this.encryptionScope, - this.requestHeaders == null ? "" : formatRequestHeaders(this.requestHeaders, includeValuesInPairs), + this.requestHeaders == null ? "" : formatRequestHeaders(this.requestHeaders, true), this.requestQueryParameters == null ? "" - : formatRequestQueryParameters(this.requestQueryParameters, includeValuesInPairs), + : formatRequestQueryParameters(this.requestQueryParameters, true), this.cacheControl == null ? "" : this.cacheControl, this.contentDisposition == null ? "" : this.contentDisposition, this.contentEncoding == null ? "" : this.contentEncoding, diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 26ee6bbebf40..444b37b63328 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -997,7 +997,8 @@ public void blobDynamicUserDelegationSas() { liveTestScenarioWithRetry(() -> { // Create container and blob using OAuth service client BlobServiceAsyncClient oauthService = getOAuthServiceAsyncClient(); - BlobContainerAsyncClient oauthContainer = oauthService.getBlobContainerAsyncClient(cc.getBlobContainerName()); + BlobContainerAsyncClient oauthContainer + = oauthService.getBlobContainerAsyncClient(cc.getBlobContainerName()); BlobAsyncClient oauthBlob = oauthContainer.getBlobAsyncClient(blobName); // Define request headers and query parameters @@ -1026,7 +1027,7 @@ public void blobDynamicUserDelegationSas() { String keyTid = testResourceNamer.recordValueFromConfig(r.getSignedTenantId()); r.setSignedTenantId(keyTid); - String blobToken = ccAsync.generateUserDelegationSas(sasValues, r); + String blobToken = sasClient.generateUserDelegationSas(sasValues, r); // Create blob client with SAS token and custom policy BlobAsyncClient identityBlob = new BlobClientBuilder().endpoint(oauthBlob.getBlobUrl()) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java index 4793b65cd443..973da107fa02 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java @@ -169,7 +169,6 @@ public static String formatRequestQueryParameters(Map requestQue return String.join(",", requestQueryParameters.keySet()); } - /** * Formats a list of keys into a comma separated string. * diff --git a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java index 6047743a2103..d02435b502ec 100644 --- a/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java +++ b/sdk/storage/azure-storage-file-datalake/src/main/java/com/azure/storage/file/datalake/implementation/util/DataLakeSasImplUtil.java @@ -259,9 +259,9 @@ private String encode(UserDelegationKey userDelegationKey, String signature) { tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_SIGNATURE, signature); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_ENCRYPTION_SCOPE, this.encryptionScope); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_HEADERS, - formatRequestHeaders(this.requestHeaders, true)); + formatRequestHeaders(this.requestHeaders, false)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_REQUEST_QUERY_PARAMETERS, - formatRequestQueryParameters(this.requestQueryParameters, true)); + formatRequestQueryParameters(this.requestQueryParameters, false)); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CACHE_CONTROL, this.cacheControl); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_DISPOSITION, this.contentDisposition); tryAppendQueryParameter(sb, Constants.UrlConstants.SAS_CONTENT_ENCODING, this.contentEncoding); diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/DataLakeTestBase.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/DataLakeTestBase.java index c7d419313413..b7707120dd60 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/DataLakeTestBase.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/DataLakeTestBase.java @@ -20,6 +20,7 @@ import com.azure.core.util.CoreUtils; import com.azure.storage.blob.models.BlobErrorCode; import com.azure.storage.common.StorageSharedKeyCredential; +import com.azure.storage.common.Utility; import com.azure.storage.common.implementation.Constants; import com.azure.storage.common.policy.RequestRetryOptions; import com.azure.storage.common.test.shared.StorageCommonTestUtils; @@ -51,6 +52,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -833,4 +835,26 @@ protected static void validatePropsSet(DataLakeServiceProperties sent, DataLakeS received.getStaticWebsite().getErrorDocument404Path()); } } + + public static HttpPipelinePolicy getAddHeadersAndQueryPolicy(Map requestHeaders, + Map requestQueryParams) { + // Create policy to add headers and query params to request + return (context, next) -> { + // Add request headers + for (Map.Entry entry : requestHeaders.entrySet()) { + context.getHttpRequest().setHeader(HttpHeaderName.fromString(entry.getKey()), entry.getValue()); + } + + // Add query parameters + String extraQuery = requestQueryParams.entrySet() + .stream() + .map(e -> Utility.urlEncode(e.getKey()) + "=" + Utility.urlEncode(e.getValue())) + .collect(Collectors.joining("&")); + + String currentUrl = context.getHttpRequest().getUrl().toString(); + context.getHttpRequest().setUrl(currentUrl + "&" + extraQuery); + + return next.process(); + }; + } } diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java index 71281779ca9c..336fa1834e6c 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java @@ -38,6 +38,8 @@ import java.time.OffsetDateTime; import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import static com.azure.storage.common.test.shared.StorageCommonTestUtils.getOidFromToken; import static org.junit.jupiter.api.Assertions.assertArrayEquals; @@ -845,4 +847,93 @@ public void canUseSasToAuthenticate() { .verifyComplete(); } + @Test + @LiveOnly + @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-02-06") + public void dataLakeFileSystemDynamicUserDelegationSas() { + liveTestScenarioWithRetry(() -> { + // Define request headers and query parameters + Map requestHeaders = new HashMap<>(); + requestHeaders.put("foo$", "bar!"); + requestHeaders.put("company", "msft"); + requestHeaders.put("city", "redmond,atlanta,reston"); + + Map requestQueryParams = new HashMap<>(); + requestQueryParams.put("hello$", "world!"); + requestQueryParams.put("check", "spelling"); + requestQueryParams.put("firstName", "john,Tim"); + + // Generate user delegation SAS with request headers and query params + FileSystemSasPermission permissions = new FileSystemSasPermission().setReadPermission(true); + OffsetDateTime expiryTime = testResourceNamer.now().plusHours(1); + + DataLakeServiceSasSignatureValues sasValues + = new DataLakeServiceSasSignatureValues(expiryTime, permissions).setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParams); + + Mono response + = getOAuthServiceAsyncClient().getUserDelegationKey(null, expiryTime).flatMap(r -> { + r.setSignedObjectId(testResourceNamer.recordValueFromConfig(r.getSignedObjectId())); + r.setSignedTenantId(testResourceNamer.recordValueFromConfig(r.getSignedTenantId())); + + String sasWithPermissions = dataLakeFileSystemClient.generateUserDelegationSas(sasValues, r); + + DataLakeFileAsyncClient client + = new DataLakeFileSystemClientBuilder().endpoint(dataLakeFileSystemClient.getFileSystemUrl()) + .sasToken(sasWithPermissions) + .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) + .buildAsyncClient() + .getFileAsyncClient(pathName); + + return client.getProperties(); + + }); + StepVerifier.create(response).expectNextCount(1).verifyComplete(); + }); + } + + @Test + @LiveOnly + @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-02-06") + public void dataLakeFileDynamicUserDelegationSas() { + liveTestScenarioWithRetry(() -> { + // Define request headers and query parameters + Map requestHeaders = new HashMap<>(); + requestHeaders.put("foo$", "bar!"); + requestHeaders.put("company", "msft"); + requestHeaders.put("city", "redmond,atlanta,reston"); + + Map requestQueryParams = new HashMap<>(); + requestQueryParams.put("hello$", "world!"); + requestQueryParams.put("check", "spelling"); + requestQueryParams.put("firstName", "john,Tim"); + + // Generate user delegation SAS with request headers and query params + PathSasPermission permissions = new PathSasPermission().setReadPermission(true); + OffsetDateTime expiryTime = testResourceNamer.now().plusHours(1); + + DataLakeServiceSasSignatureValues sasValues + = new DataLakeServiceSasSignatureValues(expiryTime, permissions).setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParams); + + Mono response + = getOAuthServiceAsyncClient().getUserDelegationKey(null, expiryTime).flatMap(r -> { + r.setSignedObjectId(testResourceNamer.recordValueFromConfig(r.getSignedObjectId())); + r.setSignedTenantId(testResourceNamer.recordValueFromConfig(r.getSignedTenantId())); + + String sasWithPermissions = sasClient.generateUserDelegationSas(sasValues, r); + + DataLakeFileAsyncClient client + = new DataLakePathClientBuilder().endpoint(sasClient.getFileUrl()) + .sasToken(sasWithPermissions) + .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) + .buildFileAsyncClient(); + + return client.getProperties(); + }); + + StepVerifier.create(response).expectNextCount(1).verifyComplete(); + }); + } + } diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 8c25d57fd2b0..65194e8794ac 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -42,6 +42,7 @@ import java.time.ZoneOffset; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -890,4 +891,84 @@ public void canUseSasToAuthenticate() { .getProperties()); } + @Test + @LiveOnly + @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-02-06") + public void dataLakeFileSystemDynamicUserDelegationSas() { + liveTestScenarioWithRetry(() -> { + // Define request headers and query parameters + Map requestHeaders = new HashMap<>(); + requestHeaders.put("foo$", "bar!"); + requestHeaders.put("company", "msft"); + requestHeaders.put("city", "redmond,atlanta,reston"); + + Map requestQueryParams = new HashMap<>(); + requestQueryParams.put("hello$", "world!"); + requestQueryParams.put("check", "spelling"); + requestQueryParams.put("firstName", "john,Tim"); + + // Generate user delegation SAS with request headers and query params + FileSystemSasPermission permissions = new FileSystemSasPermission().setReadPermission(true); + OffsetDateTime expiryTime = testResourceNamer.now().plusHours(1); + + UserDelegationKey key = getOAuthServiceClient().getUserDelegationKey(null, expiryTime); + key.setSignedObjectId(testResourceNamer.recordValueFromConfig(key.getSignedObjectId())); + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + + DataLakeServiceSasSignatureValues sasValues + = new DataLakeServiceSasSignatureValues(expiryTime, permissions).setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParams); + + String sasWithPermissions = dataLakeFileSystemClient.generateUserDelegationSas(sasValues, key); + + DataLakeFileClient client + = new DataLakeFileSystemClientBuilder().endpoint(dataLakeFileSystemClient.getFileSystemUrl()) + .sasToken(sasWithPermissions) + .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) + .buildClient() + .getFileClient(pathName); + + assertDoesNotThrow(() -> client.getProperties()); + }); + } + + @Test + @LiveOnly + @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-02-06") + public void dataLakeFileDynamicUserDelegationSas() { + liveTestScenarioWithRetry(() -> { + // Define request headers and query parameters + Map requestHeaders = new HashMap<>(); + requestHeaders.put("foo$", "bar!"); + requestHeaders.put("company", "msft"); + requestHeaders.put("city", "redmond,atlanta,reston"); + + Map requestQueryParams = new HashMap<>(); + requestQueryParams.put("hello$", "world!"); + requestQueryParams.put("check", "spelling"); + requestQueryParams.put("firstName", "john,Tim"); + + // Generate user delegation SAS with request headers and query params + PathSasPermission permissions = new PathSasPermission().setReadPermission(true); + OffsetDateTime expiryTime = testResourceNamer.now().plusHours(1); + + UserDelegationKey key = getOAuthServiceClient().getUserDelegationKey(null, expiryTime); + key.setSignedObjectId(testResourceNamer.recordValueFromConfig(key.getSignedObjectId())); + key.setSignedTenantId(testResourceNamer.recordValueFromConfig(key.getSignedTenantId())); + + DataLakeServiceSasSignatureValues sasValues + = new DataLakeServiceSasSignatureValues(expiryTime, permissions).setRequestHeaders(requestHeaders) + .setRequestQueryParameters(requestQueryParams); + + String sasWithPermissions = sasClient.generateUserDelegationSas(sasValues, key); + + DataLakeFileClient client = new DataLakePathClientBuilder().endpoint(sasClient.getFileUrl()) + .sasToken(sasWithPermissions) + .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) + .buildFileClient(); + + assertDoesNotThrow(() -> client.getProperties()); + }); + } + } From 9900fefd8f8fb696c2625049aee1ae2b56e16b20 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Fri, 6 Feb 2026 11:58:46 -0800 Subject: [PATCH 34/37] spotless --- .../com/azure/storage/file/datalake/SasAsyncTests.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java index 336fa1834e6c..86122cfff6f1 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java @@ -923,11 +923,10 @@ public void dataLakeFileDynamicUserDelegationSas() { String sasWithPermissions = sasClient.generateUserDelegationSas(sasValues, r); - DataLakeFileAsyncClient client - = new DataLakePathClientBuilder().endpoint(sasClient.getFileUrl()) - .sasToken(sasWithPermissions) - .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) - .buildFileAsyncClient(); + DataLakeFileAsyncClient client = new DataLakePathClientBuilder().endpoint(sasClient.getFileUrl()) + .sasToken(sasWithPermissions) + .addPolicy(getAddHeadersAndQueryPolicy(requestHeaders, requestQueryParams)) + .buildFileAsyncClient(); return client.getProperties(); }); From 899659ff39412a0f82a32b0c49d307593a978f23 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Fri, 6 Feb 2026 12:21:50 -0800 Subject: [PATCH 35/37] style and assets --- sdk/storage/azure-storage-blob/assets.json | 2 +- .../common/test/shared/SasTestData.java | 52 ++++++++++++++----- 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index c8bfbc0fb874..076652385cdf 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_8c8c6e5dfd" + "Tag": "java/storage/azure-storage-blob_e5357308ad" } diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java index 15ce031e6b7d..ccc76843cff0 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/SasTestData.java @@ -105,19 +105,45 @@ public SasTestData setExpectedStringToSign(String expectedStringToSign) { return this; } - public OffsetDateTime getStartTime() { return startTime; } - public String getIdentifier() { return identifier; } - public SasIpRange getIpRange() { return ipRange; } - public SasProtocol getProtocol() { return protocol; } - public String getSnapshotId() { return snapshotId; } - public String getCacheControl() { return cacheControl; } - public String getDisposition() { return disposition; } - public String getEncoding() { return encoding; } - public String getLanguage() { return language; } - public String getType() { return type; } - public String getVersionId() { return versionId; } - public String getEncryptionScope() { return encryptionScope; } - public String getExpectedStringToSign() { return expectedStringToSign; } + public OffsetDateTime getStartTime() { + return startTime; + } + public String getIdentifier() { + return identifier; + } + public SasIpRange getIpRange() { + return ipRange; + } + public SasProtocol getProtocol() { + return protocol; + } + public String getSnapshotId() { + return snapshotId; + } + public String getCacheControl() { + return cacheControl; + } + public String getDisposition() { + return disposition; + } + public String getEncoding() { + return encoding; + } + public String getLanguage() { + return language; + } + public String getType() { + return type; + } + public String getVersionId() { + return versionId; + } + public String getEncryptionScope() { + return encryptionScope; + } + public String getExpectedStringToSign() { + return expectedStringToSign; + } /** * Converts to Arguments for regular SAS tests. From f0dfb253e4e361167b5187d225f16d95e486a413 Mon Sep 17 00:00:00 2001 From: Isabelle <141270045+ibrandes@users.noreply.github.com> Date: Fri, 6 Feb 2026 14:07:41 -0800 Subject: [PATCH 36/37] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../test/java/com/azure/storage/blob/SasAsyncClientTests.java | 2 +- .../src/test/java/com/azure/storage/blob/SasClientTests.java | 2 +- .../storage/common/test/shared/UserDelegationSasTestData.java | 4 ++-- .../java/com/azure/storage/file/datalake/SasAsyncTests.java | 2 +- .../test/java/com/azure/storage/file/datalake/SasTests.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java index 444b37b63328..8a882a90c104 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasAsyncClientTests.java @@ -992,7 +992,7 @@ public void canUseSasToAuthenticate() { // RBAC replication lag @Test @LiveOnly - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-02-06") + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") public void blobDynamicUserDelegationSas() { liveTestScenarioWithRetry(() -> { // Create container and blob using OAuth service client diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java index 8963cdc1ec4e..267ebe448015 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/SasClientTests.java @@ -905,7 +905,7 @@ public void canUseSasToAuthenticate() { // RBAC replication lag @Test @LiveOnly - @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-02-06") + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-04-06") public void blobDynamicUserDelegationSas() { liveTestScenarioWithRetry(() -> { // Create container and blob using OAuth service client diff --git a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java index a0b6b7dbe741..06e66e554d49 100644 --- a/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java +++ b/sdk/storage/azure-storage-common/src/test-shared/java/com/azure/storage/common/test/shared/UserDelegationSasTestData.java @@ -210,8 +210,8 @@ requestHeaders, requestQueryParameters, getExpectedStringToSign() } /* - We test string to sign functionality directly related toUserDelegation sas specific parameters - */ + * We test string-to-sign functionality directly related to user delegation SAS-specific parameters. + */ public static Stream blobSasImplUtilStringToSignUserDelegationKeySupplier() { // Use LinkedHashMap to ensure deterministic iteration order Map singleHeader = new LinkedHashMap<>(); diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java index 86122cfff6f1..14281111e0fc 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasAsyncTests.java @@ -894,7 +894,7 @@ public void dataLakeFileSystemDynamicUserDelegationSas() { @Test @LiveOnly - @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-02-06") + @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-04-06") public void dataLakeFileDynamicUserDelegationSas() { liveTestScenarioWithRetry(() -> { // Define request headers and query parameters diff --git a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java index 65194e8794ac..c36106c0e6e1 100644 --- a/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java +++ b/sdk/storage/azure-storage-file-datalake/src/test/java/com/azure/storage/file/datalake/SasTests.java @@ -893,7 +893,7 @@ public void canUseSasToAuthenticate() { @Test @LiveOnly - @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-02-06") + @RequiredServiceVersion(clazz = DataLakeServiceVersion.class, min = "2026-04-06") public void dataLakeFileSystemDynamicUserDelegationSas() { liveTestScenarioWithRetry(() -> { // Define request headers and query parameters From 46fe77d60abb75aa9750f7507329378842b9c1d8 Mon Sep 17 00:00:00 2001 From: Isabelle Date: Fri, 6 Feb 2026 14:23:02 -0800 Subject: [PATCH 37/37] making new query param values deterministic --- .../common/implementation/SasImplUtils.java | 30 ++++++++++++++----- .../implementation/SasImplUtilsTests.java | 8 ++--- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java index 973da107fa02..20228a9e660a 100644 --- a/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java +++ b/sdk/storage/azure-storage-common/src/main/java/com/azure/storage/common/implementation/SasImplUtils.java @@ -131,18 +131,25 @@ public static Map parseQueryString(String queryParams) { * * Version 2026-04-06 and later (Blob Storage and Data Lake Storage) */ - - public static String formatRequestHeaders(Map requestHeaders, Boolean includeKeyValues) { + public static String formatRequestHeaders(Map requestHeaders, boolean includeKeyValues) { if (requestHeaders == null || requestHeaders.isEmpty()) { return null; } + + // Ensure deterministic ordering by header name for SAS signing. + List sortedKeys = new ArrayList<>(requestHeaders.keySet()); + sortedKeys.sort(String::compareTo); + if (includeKeyValues) { StringBuilder sb = new StringBuilder(); - requestHeaders.forEach((key, value) -> sb.append(key).append(":").append(value).append("\n")); + for (String key : sortedKeys) { + String value = requestHeaders.get(key); + sb.append(key).append(':').append(value).append('\n'); + } return sb.toString(); } - return String.join(",", requestHeaders.keySet()); + return String.join(",", sortedKeys); } /** @@ -157,16 +164,25 @@ public static String formatRequestHeaders(Map requestHeaders, Bo * Version 2026-04-06 and later (Blob Storage and Data Lake Storage) */ public static String formatRequestQueryParameters(Map requestQueryParameters, - Boolean includeKeyValues) { + boolean includeKeyValues) { if (requestQueryParameters == null || requestQueryParameters.isEmpty()) { return null; } + + // Ensure deterministic ordering by parameter name for SAS signing. + List sortedKeys = new ArrayList<>(requestQueryParameters.keySet()); + sortedKeys.sort(String::compareTo); + if (includeKeyValues) { StringBuilder sb = new StringBuilder(); - requestQueryParameters.forEach((key, value) -> sb.append("\n").append(key).append(":").append(value)); + for (String key : sortedKeys) { + String value = requestQueryParameters.get(key); + sb.append('\n').append(key).append(':').append(value); + } return sb.toString(); } - return String.join(",", requestQueryParameters.keySet()); + + return String.join(",", sortedKeys); } /** diff --git a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java index 2b2fae0fb4a6..34934f6568d4 100644 --- a/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java +++ b/sdk/storage/azure-storage-common/src/test/java/com/azure/storage/common/implementation/SasImplUtilsTests.java @@ -27,12 +27,12 @@ public void setup() { @Test public void formatRequestHeadersNullReturnsNull() { - assertNull(SasImplUtils.formatRequestHeaders(null, null)); + assertNull(SasImplUtils.formatRequestHeaders(null, false)); } @Test public void formatRequestHeadersEmptyReturnsNull() { - assertNull(SasImplUtils.formatRequestHeaders(requestHeaders, null)); + assertNull(SasImplUtils.formatRequestHeaders(requestHeaders, false)); } @Test @@ -90,12 +90,12 @@ public void formatRequestHeaders() { @Test public void formatRequestQueryParamsNullReturnsNull() { - assertNull(SasImplUtils.formatRequestQueryParameters(null, null)); + assertNull(SasImplUtils.formatRequestQueryParameters(null, false)); } @Test public void formatRequestQueryParamsEmptyReturnsNull() { - assertNull(SasImplUtils.formatRequestQueryParameters(requestQueryParams, null)); + assertNull(SasImplUtils.formatRequestQueryParameters(requestQueryParams, false)); } @Test