All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.auth.AbstractAWSSigner Maven / Gradle / Ivy

Go to download

The Amazon Web Services SDK for Java provides Java APIs for building software on AWS' cost-effective, scalable, and reliable infrastructure products. The AWS Java SDK allows developers to code against APIs for all of Amazon's infrastructure web services (Amazon S3, Amazon EC2, Amazon SQS, Amazon Relational Database Service, Amazon AutoScaling, etc).

The newest version!
/*
 * Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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.amazonaws.auth;

import static com.amazonaws.util.StringUtils.UTF8;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URI;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

import com.amazonaws.AmazonClientException;
import com.amazonaws.Request;
import com.amazonaws.SDKGlobalConfiguration;
import com.amazonaws.util.HttpUtils;
import com.amazonaws.util.StringInputStream;

/**
 * Abstract base class for AWS signing protocol implementations. Provides
 * utilities commonly needed by signing protocols such as computing
 * canonicalized host names, query string parameters, etc.
 * 

* Not intended to be sub-classed by developers. */ public abstract class AbstractAWSSigner implements Signer { /** * Computes an RFC 2104-compliant HMAC signature and returns the result as a * Base64 encoded string. */ protected String signAndBase64Encode(String data, String key, SigningAlgorithm algorithm) throws AmazonClientException { return signAndBase64Encode(data.getBytes(UTF8), key, algorithm); } /** * Computes an RFC 2104-compliant HMAC signature for an array of bytes and * returns the result as a Base64 encoded string. */ protected String signAndBase64Encode(byte[] data, String key, SigningAlgorithm algorithm) throws AmazonClientException { try { byte[] signature = sign(data, key.getBytes(UTF8), algorithm); return new String(Base64.encodeBase64(signature)); } catch (Exception e) { throw new AmazonClientException("Unable to calculate a request signature: " + e.getMessage(), e); } } public byte[] sign(String stringData, byte[] key, SigningAlgorithm algorithm) throws AmazonClientException { try { byte[] data = stringData.getBytes(UTF8); return sign(data, key, algorithm); } catch (Exception e) { throw new AmazonClientException("Unable to calculate a request signature: " + e.getMessage(), e); } } protected byte[] sign(byte[] data, byte[] key, SigningAlgorithm algorithm) throws AmazonClientException { try { Mac mac = Mac.getInstance(algorithm.toString()); mac.init(new SecretKeySpec(key, algorithm.toString())); return mac.doFinal(data); } catch (Exception e) { throw new AmazonClientException("Unable to calculate a request signature: " + e.getMessage(), e); } } /** * Hashes the string contents (assumed to be UTF-8) using the SHA-256 * algorithm. * * @param text * The string to hash. * * @return The hashed bytes from the specified string. * * @throws AmazonClientException * If the hash cannot be computed. */ public byte[] hash(String text) throws AmazonClientException { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(text.getBytes(UTF8)); return md.digest(); } catch (Exception e) { throw new AmazonClientException("Unable to compute hash while signing request: " + e.getMessage(), e); } } protected byte[] hash(InputStream input) throws AmazonClientException { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); DigestInputStream digestInputStream = new DigestInputStream(input, md); byte[] buffer = new byte[1024]; while (digestInputStream.read(buffer) > -1); return digestInputStream.getMessageDigest().digest(); } catch (Exception e) { throw new AmazonClientException("Unable to compute hash while signing request: " + e.getMessage(), e); } } /** * Hashes the binary data using the SHA-256 algorithm. * * @param data * The binary data to hash. * * @return The hashed bytes from the specified data. * * @throws AmazonClientException * If the hash cannot be computed. */ public byte[] hash(byte[] data) throws AmazonClientException { try { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(data); return md.digest(); } catch (Exception e) { throw new AmazonClientException("Unable to compute hash while signing request: " + e.getMessage(), e); } } /** * Examines the specified query string parameters and returns a * canonicalized form. *

* The canonicalized query string is formed by first sorting all the query * string parameters, then URI encoding both the key and value and then * joining them, in order, separating key value pairs with an '&'. * * @param parameters * The query string parameters to be canonicalized. * * @return A canonicalized form for the specified query string parameters. */ protected String getCanonicalizedQueryString(Map parameters) { SortedMap sorted = new TreeMap(); Iterator> pairs = parameters.entrySet().iterator(); while (pairs.hasNext()) { Map.Entry pair = pairs.next(); String key = pair.getKey(); String value = pair.getValue(); sorted.put(HttpUtils.urlEncode(key, false), HttpUtils.urlEncode(value, false)); } StringBuilder builder = new StringBuilder(); pairs = sorted.entrySet().iterator(); while (pairs.hasNext()) { Map.Entry pair = pairs.next(); builder.append(pair.getKey()); builder.append("="); builder.append(pair.getValue()); if (pairs.hasNext()) { builder.append("&"); } } return builder.toString(); } protected String getCanonicalizedQueryString(Request request) { /* * If we're using POST and we don't have any request payload content, * then any request query parameters will be sent as the payload, and * not in the actual query string. */ if (HttpUtils.usePayloadForQueryParameters(request)) return ""; else return this.getCanonicalizedQueryString(request.getParameters()); } /** * Returns the request's payload as binary data. * * @param request * The request * @return The data from the request's payload, as binary data. */ protected byte[] getBinaryRequestPayload(Request request) { if (HttpUtils.usePayloadForQueryParameters(request)) { String encodedParameters = HttpUtils.encodeParameters(request); if (encodedParameters == null) return new byte[0]; return encodedParameters.getBytes(UTF8); } return getBinaryRequestPayloadWithoutQueryParams(request); } /** * Returns the request's payload as a String. * * @param request * The request * @return The data from the request's payload, as a string. */ protected String getRequestPayload(Request request) { return newString(getBinaryRequestPayload(request)); } /** * Returns the request's payload contents as a String, without processing * any query string params (i.e. no form encoding for query params). * * @param request * The request * @return the request's payload contents as a String, not including any * form encoding of query string params. */ protected String getRequestPayloadWithoutQueryParams(Request request) { return newString(getBinaryRequestPayloadWithoutQueryParams(request)); } /** * Returns the request's payload contents as binary data, without processing * any query string params (i.e. no form encoding for query params). * * @param request * The request * @return The request's payload contents as binary data, not including any * form encoding of query string params. */ protected byte[] getBinaryRequestPayloadWithoutQueryParams(Request request) { InputStream content = getBinaryRequestPayloadStreamWithoutQueryParams(request); try { content.mark(-1); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024 * 5]; while (true) { int bytesRead = content.read(buffer); if (bytesRead == -1) break; byteArrayOutputStream.write(buffer, 0, bytesRead); } byteArrayOutputStream.close(); content.reset(); return byteArrayOutputStream.toByteArray(); } catch (Exception e) { throw new AmazonClientException("Unable to read request payload to sign request: " + e.getMessage(), e); } } protected InputStream getBinaryRequestPayloadStream(Request request) { if (HttpUtils.usePayloadForQueryParameters(request)) { String encodedParameters = HttpUtils.encodeParameters(request); if (encodedParameters == null) return new ByteArrayInputStream(new byte[0]); return new ByteArrayInputStream( encodedParameters.getBytes(UTF8)); } return getBinaryRequestPayloadStreamWithoutQueryParams(request); } protected InputStream getBinaryRequestPayloadStreamWithoutQueryParams(Request request) { try { InputStream content = request.getContent(); if (content == null) return new ByteArrayInputStream(new byte[0]); if (content instanceof StringInputStream) { return content; } if (!content.markSupported()) { throw new AmazonClientException("Unable to read request payload to sign request."); } return request.getContent(); } catch (Exception e) { throw new AmazonClientException("Unable to read request payload to sign request: " + e.getMessage(), e); } } protected String getCanonicalizedResourcePath(String resourcePath) { return getCanonicalizedResourcePath(resourcePath, true); } protected String getCanonicalizedResourcePath(String resourcePath, boolean urlEncode) { if (resourcePath == null || resourcePath.length() == 0) { return "/"; } else { String value = urlEncode ? HttpUtils.urlEncode(resourcePath, true) : resourcePath; if (value.startsWith("/")) { return value; } else { return "/".concat(value); } } } protected String getCanonicalizedEndpoint(URI endpoint) { String endpointForStringToSign = endpoint.getHost().toLowerCase(); /* * Apache HttpClient will omit the port in the Host header for default * port values (i.e. 80 for HTTP and 443 for HTTPS) even if we * explicitly specify it, so we need to be careful that we use the same * value here when we calculate the string to sign and in the Host * header we send in the HTTP request. */ if (HttpUtils.isUsingNonDefaultPort(endpoint)) { endpointForStringToSign += ":" + endpoint.getPort(); } return endpointForStringToSign; } /** * Loads the individual access key ID and secret key from the specified * credentials, ensuring that access to the credentials is synchronized on * the credentials object itself, and trimming any extra whitespace from the * credentials. *

* Returns either a {@link BasicSessionCredentials} or a * {@link BasicAWSCredentials} object, depending on the input type. * * @param credentials * @return A new credentials object with the sanitized credentials. */ protected AWSCredentials sanitizeCredentials(AWSCredentials credentials) { String accessKeyId = null; String secretKey = null; String token = null; synchronized (credentials) { accessKeyId = credentials.getAWSAccessKeyId(); secretKey = credentials.getAWSSecretKey(); if ( credentials instanceof AWSSessionCredentials ) { token = ((AWSSessionCredentials) credentials).getSessionToken(); } } if (secretKey != null) secretKey = secretKey.trim(); if (accessKeyId != null) accessKeyId = accessKeyId.trim(); if (token != null) token = token.trim(); if (credentials instanceof AWSSessionCredentials) { return new BasicSessionCredentials(accessKeyId, secretKey, token); } return new BasicAWSCredentials(accessKeyId, secretKey); } /** * Safely converts a UTF-8 encoded byte array into a String. * * @param bytes UTF-8 encoded binary character data. * * @return The converted String object. */ protected String newString(byte[] bytes) { return new String(bytes, UTF8); } protected Date getSignatureDate(int timeOffset) { Date dateValue = new Date(); if (timeOffset != 0) { long epochMillis = dateValue.getTime(); epochMillis -= timeOffset*1000; dateValue = new Date(epochMillis); } return dateValue; } protected int getTimeOffset(Request request) { int timeOffset = request.getTimeOffset(); if(SDKGlobalConfiguration.getGlobalTimeOffset() != 0) { // if global time offset is set then use that (For clock skew issues) timeOffset = SDKGlobalConfiguration.getGlobalTimeOffset(); } return timeOffset; } /** * Adds session credentials to the request given. * * @param request * The request to add session credentials information to * @param credentials * The session credentials to add to the request */ protected abstract void addSessionCredentials(Request request, AWSSessionCredentials credentials); }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy