TableSasUtils.java
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.data.tables.implementation;
import com.azure.core.credential.AzureNamedKeyCredential;
import com.azure.core.http.HttpPipeline;
import com.azure.data.tables.TableAzureNamedKeyCredentialPolicy;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.OffsetDateTime;
import java.util.Base64;
/**
* This class provides helper methods used when generating SAS.
*/
public class TableSasUtils {
private static final String STRING_TO_SIGN_LOG_INFO_MESSAGE = "The string to sign computed by the SDK is: {}{}";
private static final String STRING_TO_SIGN_LOG_WARNING_MESSAGE = "Please remember to disable '{}' before going "
+ "to production as this string can potentially contain PII.";
/**
* Shared helper method to append a SAS query parameter.
*
* @param sb The {@link StringBuilder} to append to.
* @param param The {@code String} parameter to append.
* @param value The value of the parameter to append.
*/
public static void tryAppendQueryParameter(StringBuilder sb, String param, Object value) {
if (value != null) {
if (sb.length() != 0) {
sb.append('&');
}
sb.append(TableUtils.urlEncode(param)).append('=').append(TableUtils.urlEncode(value.toString()));
}
}
/**
* Formats date time SAS query parameters.
*
* @param dateTime The SAS date time.
* @return A String representing the SAS date time.
*/
public static String formatQueryParameterDate(OffsetDateTime dateTime) {
if (dateTime == null) {
return null;
} else {
return StorageConstants.ISO_8601_UTC_DATE_FORMATTER.format(dateTime);
}
}
/**
* Extracts the {@link AzureNamedKeyCredential} from a {@link HttpPipeline}
*
* @param pipeline An {@link HttpPipeline} to extract an {@link AzureNamedKeyCredential} from.
*
* @return The extracted {@link AzureNamedKeyCredential}.
*/
public static AzureNamedKeyCredential extractNamedKeyCredential(HttpPipeline pipeline) {
for (int i = 0; i < pipeline.getPolicyCount(); i++) {
if (pipeline.getPolicy(i) instanceof TableAzureNamedKeyCredentialPolicy) {
TableAzureNamedKeyCredentialPolicy policy = (TableAzureNamedKeyCredentialPolicy) pipeline.getPolicy(i);
return policy.getCredential();
}
}
return null;
}
/**
* Computes a signature for the specified string using the HMAC-SHA256 algorithm.
*
* @param base64Key Base64 encoded key used to sign the string
* @param stringToSign UTF-8 encoded string to sign
*
* @return the HMAC-SHA256 encoded signature
*
* @throws RuntimeException If the HMAC-SHA256 algorithm isn't support, if the key isn't a valid Base64 encoded
* string, or the UTF-8 charset isn't supported.
*/
public static String computeHmac256(final String base64Key, final String stringToSign) {
try {
byte[] key = Base64.getDecoder().decode(base64Key);
Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
hmacSHA256.init(new SecretKeySpec(key, "HmacSHA256"));
byte[] utf8Bytes = stringToSign.getBytes(StandardCharsets.UTF_8);
return Base64.getEncoder().encodeToString(hmacSHA256.doFinal(utf8Bytes));
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
throw new RuntimeException(ex);
}
}
}