/**
* Copyright Microsoft Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.microsoft.azure.storage.core;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import com.microsoft.azure.storage.Constants;
import com.microsoft.azure.storage.OperationContext;
import com.microsoft.azure.storage.StorageCredentials;
import com.microsoft.azure.storage.StorageCredentialsAccountAndKey;
import com.microsoft.azure.storage.StorageCredentialsSharedAccessSignature;
import com.microsoft.azure.storage.StorageException;
/**
* RESERVED FOR INTERNAL USE. A helper method for StorageCredentials.
*/
public final class StorageCredentialsHelper {
/**
* RESERVED, for internal use only. Gets a value indicating whether a
* request can be signed under the Shared Key authentication scheme using
* the specified credentials.
* @return <Code>true</Code> if a request can be signed with these
* credentials; otherwise, <Code>false</Code>
*/
public static boolean canCredentialsSignRequest(final StorageCredentials creds) {
return creds.getClass().equals(StorageCredentialsAccountAndKey.class);
}
/**
* RESERVED, for internal use only. Gets a value indicating whether a
* client can be generated under the Shared Key or Shared Access Signature
* authentication schemes using the specified credentials.
* @return <Code>true</Code> if a client can be generated with these
* credentials; otherwise, <Code>false</Code>
*/
public static boolean canCredentialsGenerateClient(final StorageCredentials creds) {
return canCredentialsSignRequest(creds) || creds.getClass().equals(StorageCredentialsSharedAccessSignature.class);
}
/**
* Computes a signature for the specified string using the HMAC-SHA256 algorithm.
*
* @param value
* The UTF-8-encoded string to sign.
*
* @return A <code>String</code> that contains the HMAC-SHA256-encoded signature.
*
* @throws InvalidKeyException
* If the key is not a valid Base64-encoded string.
*/
public static synchronized String computeHmac256(final StorageCredentials creds, final String value) throws InvalidKeyException {
if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
byte[] utf8Bytes = null;
try {
utf8Bytes = value.getBytes(Constants.UTF8_CHARSET);
}
catch (final UnsupportedEncodingException e) {
throw new IllegalArgumentException(e);
}
return Base64.encode(((StorageCredentialsAccountAndKey) creds).getHmac256().doFinal(utf8Bytes));
}
else {
return null;
}
}
/**
* Signs a request using the specified operation context under the Shared Key authentication scheme.
*
* @param request
* An <code>HttpURLConnection</code> object that represents the request to sign.
* @param contentLength
* The length of the content written to the output stream. If unknown, specify -1.
* @param opContext
* An {@link OperationContext} object that represents the context for the current operation. This object
* is used to track requests to the storage service, and to provide additional runtime information about
* the operation.
*
* @throws InvalidKeyException
* If the given key is invalid.
* @throws StorageException
* If a storage service error occurred.
*/
public static void signBlobQueueAndFileRequest(final StorageCredentials creds,
final java.net.HttpURLConnection request, final long contentLength, OperationContext opContext)
throws InvalidKeyException, StorageException {
if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
opContext = opContext == null ? new OperationContext() : opContext;
request.setRequestProperty(Constants.HeaderConstants.DATE, Utility.getGMTTime());
final Canonicalizer canonicalizer = CanonicalizerFactory.getBlobQueueFileCanonicalizer(request);
final String stringToSign = canonicalizer.canonicalize(request, creds.getAccountName(), contentLength);
final String computedBase64Signature = StorageCredentialsHelper.computeHmac256(creds, stringToSign);
Logger.debug(opContext, LogConstants.SIGNING, stringToSign);
request.setRequestProperty(Constants.HeaderConstants.AUTHORIZATION,
String.format("%s %s:%s", "SharedKey", creds.getAccountName(), computedBase64Signature));
}
}
/**
* Signs a request using the specified operation context under the Shared Key authentication scheme.
*
* @param request
* An <code>HttpURLConnection</code> object that represents the request to sign.
* @param contentLength
* The length of the content written to the output stream. If unknown, specify -1.
* @param opContext
* An {@link OperationContext} object that represents the context for the current operation. This object
* is used to track requests to the storage service, and to provide additional runtime information about
* the operation.
*
* @throws InvalidKeyException
* If the given key is invalid.
* @throws StorageException
* If a storage service error occurred.
*/
public static void signTableRequest(final StorageCredentials creds, final java.net.HttpURLConnection request,
final long contentLength, OperationContext opContext) throws InvalidKeyException, StorageException {
if (creds.getClass().equals(StorageCredentialsAccountAndKey.class)) {
opContext = opContext == null ? new OperationContext() : opContext;
request.setRequestProperty(Constants.HeaderConstants.DATE, Utility.getGMTTime());
final Canonicalizer canonicalizer = CanonicalizerFactory.getTableCanonicalizer(request);
final String stringToSign = canonicalizer.canonicalize(request, creds.getAccountName(), contentLength);
final String computedBase64Signature = StorageCredentialsHelper.computeHmac256(creds, stringToSign);
Logger.debug(opContext, LogConstants.SIGNING, stringToSign);
request.setRequestProperty(Constants.HeaderConstants.AUTHORIZATION,
String.format("%s %s:%s", "SharedKey", creds.getAccountName(), computedBase64Signature));
}
}
/**
* A private default constructor. All methods of this class are static so no instances of it should ever be created.
*/
private StorageCredentialsHelper() {
//No op
}
}