From 7edd3036d26743abf44a16cc25cfc172b76ded5d Mon Sep 17 00:00:00 2001 From: Isabelle Date: Sun, 7 Dec 2025 12:12:11 -0800 Subject: [PATCH 01/16] 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 833e3e83ecbd407352fa74ca45e1d187bc43725a Mon Sep 17 00:00:00 2001 From: browndav Date: Tue, 20 Jan 2026 17:25:19 -0500 Subject: [PATCH 02/16] 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 03/16] 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 04/16] 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 05/16] 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 06/16] 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 07/16] 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 08/16] 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 09/16] 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 10/16] 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 11/16] 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 12/16] 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 13/16] 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 14/16] 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 15/16] 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 16/16] 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