com.azure.storage.blob.sas.BlobServiceSasSignatureValues Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of azure-storage-blob Show documentation
Show all versions of azure-storage-blob Show documentation
This module contains client library for Microsoft Azure Blob Storage.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.storage.blob.sas;
import com.azure.core.util.Configuration;
import com.azure.core.util.CoreUtils;
import com.azure.core.util.logging.ClientLogger;
import com.azure.storage.blob.BlobServiceVersion;
import com.azure.storage.blob.models.UserDelegationKey;
import com.azure.storage.common.Utility;
import com.azure.storage.common.implementation.Constants;
import com.azure.storage.common.implementation.StorageImplUtils;
import com.azure.storage.common.StorageSharedKeyCredential;
import com.azure.storage.common.sas.SasIpRange;
import com.azure.storage.common.sas.SasProtocol;
import java.time.OffsetDateTime;
/**
* Used to initialize parameters for a Shared Access Signature (SAS) for an Azure Blob Storage service. Once all the
* values here are set, use the appropriate SAS generation method on the desired container/blob client to obtain a
* representation of the SAS which can then be applied to a new client using the .sasToken(String) method on the
* desired client builder.
*
* @see Storage SAS overview
* @see Constructing a Service
* SAS
* @see Constructing a
* User Delegation SAS
*/
public final class BlobServiceSasSignatureValues {
/**
* The SAS blob constant.
*/
private static final String SAS_BLOB_CONSTANT = "b";
/**
* The SAS blob snapshot constant.
*/
private static final String SAS_BLOB_SNAPSHOT_CONSTANT = "bs";
/**
* The SAS blob container constant.
*/
private static final String SAS_CONTAINER_CONSTANT = "c";
private static final ClientLogger LOGGER = new ClientLogger(BlobServiceSasSignatureValues.class);
private static final String VERSION = Configuration.getGlobalConfiguration()
.get(Constants.PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION, BlobServiceVersion.getLatest().getVersion());
/**
* Pin down to highest version that worked with string to sign defined here.
*/
private static final String VERSION_DEPRECATED_SHARED_KEY_SAS_STRING_TO_SIGN =
Configuration.getGlobalConfiguration()
.get(Constants.PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION, BlobServiceVersion.V2020_10_02.getVersion());
/**
* Pin down to highest version that worked with string to sign defined here.
*/
private static final String VERSION_DEPRECATED_USER_DELEGATION_SAS_STRING_TO_SIGN =
Configuration.getGlobalConfiguration()
.get(Constants.PROPERTY_AZURE_STORAGE_SAS_SERVICE_VERSION, BlobServiceVersion.V2019_12_12.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 identifier;
private String cacheControl;
private String contentDisposition;
private String contentEncoding;
private String contentLanguage;
private String contentType;
private String preauthorizedAgentObjectId; /* saoid */
private String correlationId;
private String encryptionScope;
/**
* Creates an object with empty values for all fields.
* @deprecated Please use {@link #BlobServiceSasSignatureValues(String)},
* {@link #BlobServiceSasSignatureValues(OffsetDateTime, BlobSasPermission)}, or
* {@link #BlobServiceSasSignatureValues(OffsetDateTime, BlobContainerSasPermission)}
*/
@Deprecated
public BlobServiceSasSignatureValues() {
}
/**
* Creates an object with the specified expiry time and permissions
*
* @param expiryTime The time after which the SAS will no longer work.
* @param permissions {@link BlobContainerSasPermission} allowed by the SAS.
*/
public BlobServiceSasSignatureValues(OffsetDateTime expiryTime, BlobContainerSasPermission permissions) {
StorageImplUtils.assertNotNull("expiryTime", expiryTime);
StorageImplUtils.assertNotNull("permissions", permissions);
this.expiryTime = expiryTime;
this.permissions = permissions.toString();
}
/**
* Creates an object with the specified expiry time and permissions
*
* @param expiryTime When the SAS will no longer work
* @param permissions {@link BlobSasPermission} allowed by the SAS
*/
public BlobServiceSasSignatureValues(OffsetDateTime expiryTime, BlobSasPermission permissions) {
StorageImplUtils.assertNotNull("expiryTime", expiryTime);
StorageImplUtils.assertNotNull("permissions", permissions);
this.expiryTime = expiryTime;
this.permissions = permissions.toString();
}
/**
* Creates an object with the specified identifier.
* NOTE: Identifier can not be used for a {@link UserDelegationKey} SAS.
*
* @param identifier Name of the access policy
*/
public BlobServiceSasSignatureValues(String identifier) {
StorageImplUtils.assertNotNull("identifier", identifier);
this.identifier = identifier;
}
/**
* Creates an object with the specified values.
*
* @param version The version of the service this SAS will target. If not specified, it will default to the version
* targeted by the library.
* @param sasProtocol The {@link SasProtocol} which determines the protocols allowed by the SAS.
* @param startTime When the SAS will take effect.
* @param expiryTime The time after which the SAS will no longer work.
* @param permission The permissions string allowed by the SAS.
* @param sasIpRange The {@link SasIpRange} which determines the IP ranges that are allowed to use the SAS.
* @param identifier The name of the access policy on the container this SAS references if any.
* @param cacheControl The cache-control header for the SAS.
* @param contentDisposition The content-disposition header for the SAS.
* @param contentEncoding The content-encoding header for the SAS.
* @param contentLanguage The content-language header for the SAS.
* @param contentType The content-type header for the SAS.
* @deprecated Please use {@link #BlobServiceSasSignatureValues(String)},
* {@link #BlobServiceSasSignatureValues(OffsetDateTime, BlobSasPermission)}, or
* {@link #BlobServiceSasSignatureValues(OffsetDateTime, BlobContainerSasPermission)}
* followed by calls to the desired setters.
*/
@Deprecated
public BlobServiceSasSignatureValues(String version, SasProtocol sasProtocol, OffsetDateTime startTime,
OffsetDateTime expiryTime, String permission, SasIpRange sasIpRange, String identifier, String cacheControl,
String contentDisposition, String contentEncoding, String contentLanguage, String contentType) {
this.protocol = sasProtocol;
this.startTime = startTime;
this.expiryTime = expiryTime;
this.permissions = permission;
this.sasIpRange = sasIpRange;
this.identifier = identifier;
this.cacheControl = cacheControl;
this.contentDisposition = contentDisposition;
this.contentEncoding = contentEncoding;
this.contentLanguage = contentLanguage;
this.contentType = contentType;
}
/**
* @return the version of the service this SAS will target. If not specified, it will default to the version
* targeted by the library.
*/
public String getVersion() {
return VERSION;
}
/**
* Sets the version of the service this SAS will target. If not specified, it will default to the version targeted
* by the library.
*
* @param version Version to target
* @return the updated BlobServiceSASSignatureValues object
* @deprecated The version is set to the latest version of sas. Users should stop calling this API as it is now
* treated as a no-op.
*/
@Deprecated
public BlobServiceSasSignatureValues setVersion(String version) {
/* No-op.*/
return this;
}
/**
* @return the {@link SasProtocol} which determines the protocols allowed by the SAS.
*/
public SasProtocol getProtocol() {
return protocol;
}
/**
* Sets the {@link SasProtocol} which determines the protocols allowed by the SAS.
*
* @param protocol Protocol for the SAS
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setProtocol(SasProtocol protocol) {
this.protocol = protocol;
return this;
}
/**
* @return when the SAS will take effect.
*/
public OffsetDateTime getStartTime() {
return startTime;
}
/**
* Sets when the SAS will take effect.
*
* @param startTime When the SAS takes effect
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setStartTime(OffsetDateTime startTime) {
this.startTime = startTime;
return this;
}
/**
* @return the time after which the SAS will no longer work.
*/
public OffsetDateTime getExpiryTime() {
return expiryTime;
}
/**
* Sets the time after which the SAS will no longer work.
*
* @param expiryTime When the SAS will no longer work
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setExpiryTime(OffsetDateTime expiryTime) {
this.expiryTime = expiryTime;
return this;
}
/**
* @return the permissions string allowed by the SAS. Please refer to either {@link BlobContainerSasPermission} or
* {@link BlobSasPermission} depending on the resource being accessed for help determining the permissions allowed.
*/
public String getPermissions() {
return permissions;
}
/**
* Sets the Blob permissions allowed by the SAS.
*
* @param permissions {@link BlobSasPermission}
* @return the updated BlobServiceSASSignatureValues object
* @throws NullPointerException if {@code permissions} is null.
*/
public BlobServiceSasSignatureValues setPermissions(BlobSasPermission permissions) {
StorageImplUtils.assertNotNull("permissions", permissions);
this.permissions = permissions.toString();
return this;
}
/**
* Sets the Container permissions allowed by the SAS.
*
* @param permissions {@link BlobContainerSasPermission}
* @return the updated BlobServiceSASSignatureValues object
* @throws NullPointerException if {@code permissions} is null.
*/
public BlobServiceSasSignatureValues setPermissions(BlobContainerSasPermission permissions) {
StorageImplUtils.assertNotNull("permissions", permissions);
this.permissions = permissions.toString();
return this;
}
/**
* @return the {@link SasIpRange} which determines the IP ranges that are allowed to use the SAS.
*/
public SasIpRange getSasIpRange() {
return sasIpRange;
}
/**
* Sets the {@link SasIpRange} which determines the IP ranges that are allowed to use the SAS.
*
* @see Specifying IP Address or IP range
* @param sasIpRange Allowed IP range to set
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setSasIpRange(SasIpRange sasIpRange) {
this.sasIpRange = sasIpRange;
return this;
}
/**
* Gets the name of the container the SAS user may access.
*
* @return The name of the container the SAS user may access.
* @deprecated Container name is now auto-populated by the SAS generation methods provided on the desired
* container/blob client.
*/
@Deprecated
public String getContainerName() {
return containerName;
}
/**
* Sets the container the SAS user may access.
*
* @param containerName The name of the container.
* @return The updated BlobServiceSASSignatureValues object.
* @deprecated Please use the SAS generation methods provided on the desired container/blob client that will
* auto-populate the container name.
*/
@Deprecated
public BlobServiceSasSignatureValues setContainerName(String containerName) {
this.containerName = containerName;
return this;
}
/**
* Decodes and gets the name of the blob the SAS user may access. {@code null} or an empty string is returned when a
* creating a container SAS.
*
* @return The decoded name of the blob the SAS user may access. {@code null} or an empty string is returned when a
* creating a container SAS.
* @deprecated Blob name is now auto-populated by the SAS generation methods provided on the desired blob client.
*/
@Deprecated
public String getBlobName() {
return blobName;
}
/**
* Sets the blob the SAS user may access. Use {@code null} or an empty string to create a container SAS.
*
* @param blobName The name of the blob. Use {@code null} or an empty string to create a container SAS.
* @return The updated BlobServiceSASSignatureValues object.
* @deprecated Please use the SAS generation methods provided on the desired blob client that will auto-populate the
* blob name.
*/
@Deprecated
public BlobServiceSasSignatureValues setBlobName(String blobName) {
this.blobName = (blobName == null) ? null : Utility.urlDecode(blobName);
return this;
}
/**
* @return the specific snapshot the SAS user may access.
* @deprecated Snapshot id is now auto-populated by the SAS generation methods provided on the desired (snapshot)
* blob client.
*/
@Deprecated
public String getSnapshotId() {
return this.snapshotId;
}
/**
* Sets the specific snapshot the SAS user may access.
*
* {@link #resource} will be set to {@link #SAS_BLOB_SNAPSHOT_CONSTANT} if the passed {@code snapshotId} isn't
* {@code null} amd {@link #resource} is set to {@link #SAS_BLOB_CONSTANT}.
*
* @param snapshotId Identifier of the snapshot
* @return the updated BlobServiceSASSignatureValues object
* @deprecated Please use the SAS generation methods provided on the desired (snapshot) blob client that will
* auto-populate the snapshot id.
*/
@Deprecated
public BlobServiceSasSignatureValues setSnapshotId(String snapshotId) {
this.snapshotId = snapshotId;
if (snapshotId != null && SAS_BLOB_CONSTANT.equals(resource)) {
this.resource = SAS_BLOB_SNAPSHOT_CONSTANT;
}
return this;
}
/**
* @return the name of the access policy on the container this SAS references if any. Please see
* here
* for more information.
*/
public String getIdentifier() {
return identifier;
}
/**
* Sets the name of the access policy on the container this SAS references if any. Please see
* here
* for more information.
*
* @param identifier Name of the access policy
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setIdentifier(String identifier) {
this.identifier = identifier;
return this;
}
/**
* @return the cache-control header for the SAS.
*/
public String getCacheControl() {
return cacheControl;
}
/**
* Sets the cache-control header for the SAS.
*
* @param cacheControl Cache-Control header value
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setCacheControl(String cacheControl) {
this.cacheControl = cacheControl;
return this;
}
/**
* @return the content-disposition header for the SAS.
*/
public String getContentDisposition() {
return contentDisposition;
}
/**
* Sets the content-disposition header for the SAS.
*
* @param contentDisposition Content-Disposition header value
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setContentDisposition(String contentDisposition) {
this.contentDisposition = contentDisposition;
return this;
}
/**
* @return the content-encoding header for the SAS.
*/
public String getContentEncoding() {
return contentEncoding;
}
/**
* Sets the content-encoding header for the SAS.
*
* @param contentEncoding Content-Encoding header value
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setContentEncoding(String contentEncoding) {
this.contentEncoding = contentEncoding;
return this;
}
/**
* @return the content-language header for the SAS.
*/
public String getContentLanguage() {
return contentLanguage;
}
/**
* Sets the content-language header for the SAS.
*
* @param contentLanguage Content-Language header value
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setContentLanguage(String contentLanguage) {
this.contentLanguage = contentLanguage;
return this;
}
/**
* @return the content-type header for the SAS.
*/
public String getContentType() {
return contentType;
}
/**
* Sets the content-type header for the SAS.
*
* @param contentType Content-Type header value
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setContentType(String contentType) {
this.contentType = contentType;
return this;
}
/**
* @return The AAD object ID of a user assumed to be authorized by the owner of the user delegation key to perform
* the action granted by the SAS token. The service will validate the SAS token and ensure that the owner of the
* user delegation key has the required permissions before granting access but no additional permission check for
* the agent object id will be performed.
*/
public String getPreauthorizedAgentObjectId() {
return preauthorizedAgentObjectId;
}
/**
* Sets the AAD object ID of a user assumed to be authorized by the owner of the user delegation key to perform the
* action granted by the SAS token.
*
* @param preauthorizedAgentObjectId The AAD object ID of a user assumed to be authorized by the owner of the user
* delegation key to perform the action granted by the SAS token. The service will validate the SAS token and
* ensure that the owner of the user delegation key has the required permissions before granting access but no
* additional permission check for the agent object id will be performed.
* @return the updated BlobServiceSASSignatureValues object
*/
public BlobServiceSasSignatureValues setPreauthorizedAgentObjectId(String preauthorizedAgentObjectId) {
this.preauthorizedAgentObjectId = preauthorizedAgentObjectId;
return this;
}
/**
* @return the correlation id value for the SAS.
*/
public String getCorrelationId() {
return correlationId;
}
/**
* Sets the correlation id value for the SAS.
*
* Note: This parameter is only valid for user delegation SAS.
*
* @param correlationId A correlation ID used to correlate the storage audit logs with the audit logs used by the
* principal generating and distributing SAS.
* @return the updated BlobServiceSasSignatureValues object
*/
public BlobServiceSasSignatureValues setCorrelationId(String correlationId) {
this.correlationId = correlationId;
return this;
}
/**
* Uses an account's shared key credential to sign these signature values to produce the proper SAS query
* parameters.
*
* Notes on SAS generation
*
* - If {@link #setIdentifier(String) identifier} is set, {@link #setExpiryTime(OffsetDateTime) expiryTime} and
* permissions should not be set. These values are inherited from the stored access policy.
* - Otherwise, {@link #setExpiryTime(OffsetDateTime) expiryTime} and {@link #getPermissions() permissions} must
* be set.
*
*
*
* The type of SAS query parameters returned depends on the following:
*
* - If {@link #getBlobName()} is not set, container SAS query parameters are returned.
* - If {@link #getBlobName()} and {@link #getSnapshotId()} are set, blob snapshot SAS query parameters
* are returned.
* - If only {@link #getBlobName()} is set, blob SAS query parameters are returned.
*
*
* See class level JavaDocs for code snippets.
*
* @param storageSharedKeyCredentials A {@link StorageSharedKeyCredential} object used to sign the SAS values.
* @return {@link BlobServiceSasQueryParameters}
* @throws IllegalStateException If the HMAC-SHA256 algorithm isn't supported, if the key isn't a valid Base64
* encoded string, or the UTF-8 charset isn't supported.
* @throws IllegalArgumentException if {@link #getPermissions()} contains an invalid character for the SAS resource.
* @throws NullPointerException if {@code storageSharedKeyCredentials} is null.
* @deprecated Please use the generateSas(BlobServiceSasSignatureValues) method on the desired container/blob client
* after initializing {@link BlobServiceSasSignatureValues}.
*/
@Deprecated
public BlobServiceSasQueryParameters generateSasQueryParameters(
StorageSharedKeyCredential storageSharedKeyCredentials) {
StorageImplUtils.assertNotNull("storageSharedKeyCredentials", storageSharedKeyCredentials);
ensureState();
// Signature is generated on the un-url-encoded values.
final String canonicalName = getCanonicalName(storageSharedKeyCredentials.getAccountName());
final String signature = storageSharedKeyCredentials.computeHmac256(stringToSign(canonicalName));
return new BlobServiceSasQueryParameters(VERSION_DEPRECATED_SHARED_KEY_SAS_STRING_TO_SIGN, this.protocol,
this.startTime, this.expiryTime, this.sasIpRange, this.identifier, this.resource, this.permissions,
signature, this.cacheControl, this.contentDisposition, this.contentEncoding, this.contentLanguage,
this.contentType, null /* delegate */);
}
/**
* Uses a user delegation key to sign these signature values to produce the proper SAS query parameters.
*
* Notes on SAS generation
*
* - If {@link #setIdentifier(String) identifier} is set, {@link #setExpiryTime(OffsetDateTime) expiryTime} and
* permissions should not be set. These values are inherited from the stored access policy.
* - Otherwise, {@link #setExpiryTime(OffsetDateTime) expiryTime} and {@link #getPermissions() permissions} must
* be set.
*
*
*
* The type of SAS query parameters returned depends on the following:
*
* - If {@link #getBlobName()} is not set, container SAS query parameters are returned.
* - If {@link #getBlobName()} and {@link #getSnapshotId()} are set, blob snapshot SAS query parameters
* are returned.
* - If only {@link #getBlobName()} is set, blob SAS query parameters are returned.
*
*
* See class level JavaDocs for code snippets.
*
* @param delegationKey A {@link UserDelegationKey} object used to sign the SAS values.
* @param accountName Azure Storage account name to generate SAS for.
* @return {@link BlobServiceSasQueryParameters}
* @throws IllegalStateException If the HMAC-SHA256 algorithm isn't supported, if the key isn't a valid Base64
* encoded string, or the UTF-8 charset isn't supported.
* @throws IllegalArgumentException if {@link #getPermissions()} contains an invalid character for the SAS resource.
* @throws NullPointerException if {@code delegationKey} or {@code account} is null.
* @see
* Create a user delegation SAS
* @deprecated Please use the generateUserDelegationSas(BlobServiceSasSignatureValues, UserDelegationKey) method on
* the desired container/blob client after initializing {@link BlobServiceSasSignatureValues}.
*/
@Deprecated
public BlobServiceSasQueryParameters generateSasQueryParameters(UserDelegationKey delegationKey,
String accountName) {
StorageImplUtils.assertNotNull("delegationKey", delegationKey);
StorageImplUtils.assertNotNull("accountName", accountName);
ensureState();
// Signature is generated on the un-url-encoded values.
final String canonicalName = getCanonicalName(accountName);
String signature = StorageImplUtils.computeHMac256(
delegationKey.getValue(), stringToSign(delegationKey, canonicalName));
return new BlobServiceSasQueryParameters(VERSION_DEPRECATED_USER_DELEGATION_SAS_STRING_TO_SIGN, this.protocol,
this.startTime, this.expiryTime, this.sasIpRange, null /* identifier */, this.resource, this.permissions,
signature, this.cacheControl, this.contentDisposition, this.contentEncoding, this.contentLanguage,
this.contentType, delegationKey);
}
/**
* Ensures that the builder's properties are in a consistent state.
* 1. If there is no version, use latest.
* 2. 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, it is a blob resource.
* 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
*/
private void ensureState() {
if (CoreUtils.isNullOrEmpty(blobName)) {
resource = SAS_CONTAINER_CONSTANT;
} else if (snapshotId != null) {
resource = SAS_BLOB_SNAPSHOT_CONSTANT;
} else {
resource = SAS_BLOB_CONSTANT;
}
if (permissions != null) {
switch (resource) {
case SAS_BLOB_CONSTANT:
case SAS_BLOB_SNAPSHOT_CONSTANT:
permissions = BlobSasPermission.parse(permissions).toString();
break;
case SAS_CONTAINER_CONSTANT:
permissions = BlobContainerSasPermission.parse(permissions).toString();
break;
default:
// We won't reparse the permissions if we don't know the type.
LOGGER.info("Not re-parsing permissions. Resource type '{}' is unknown.", resource);
break;
}
}
}
/**
* Computes the canonical name for a container or blob resource for SAS signing.
*/
private String getCanonicalName(String account) {
// Container: "/blob/account/containername"
// Blob: "/blob/account/containername/blobname"
return CoreUtils.isNullOrEmpty(blobName)
? "/blob/" + account + "/" + containerName
: "/blob/" + account + "/" + containerName + "/" + blobName.replace('\\', '/');
}
private String stringToSign(String canonicalName) {
return String.join("\n",
this.permissions == null ? "" : 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,
this.identifier == null ? "" : this.identifier,
this.sasIpRange == null ? "" : this.sasIpRange.toString(),
this.protocol == null ? "" : this.protocol.toString(),
VERSION_DEPRECATED_SHARED_KEY_SAS_STRING_TO_SIGN, /* Pin down to version so old string to sign works. */
resource,
this.snapshotId == null ? "" : this.snapshotId,
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
);
}
private String stringToSign(final UserDelegationKey key, String canonicalName) {
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.sasIpRange == null ? "" : this.sasIpRange.toString(),
this.protocol == null ? "" : this.protocol.toString(),
VERSION_DEPRECATED_USER_DELEGATION_SAS_STRING_TO_SIGN, /* Pin down to version so old string to sign works. */
resource,
this.snapshotId == null ? "" : this.snapshotId,
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
);
}
}