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

com.amazonaws.auth.AWS3Signer 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.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.amazonaws.AmazonClientException;
import com.amazonaws.Request;
import com.amazonaws.util.DateUtils;
import com.amazonaws.util.HttpUtils;

/**
 * Signer implementation that signs requests with the AWS3 signing protocol.
 */
public class AWS3Signer extends AbstractAWSSigner {
    private static final String AUTHORIZATION_HEADER = "X-Amzn-Authorization";
    private static final String NONCE_HEADER = "x-amz-nonce";
    private static final String HTTP_SCHEME = "AWS3";
    private static final String HTTPS_SCHEME = "AWS3-HTTPS";

    /** For internal testing only - allows the request's date to be overridden for testing. */
    private String overriddenDate;

    protected static final DateUtils dateUtils = new DateUtils();
    private static final Log log = LogFactory.getLog(AWS3Signer.class);


    /**
     * Signs the specified request with the AWS3 signing protocol by using the
     * AWS account credentials specified when this object was constructed and
     * adding the required AWS3 headers to the request.
     *
     * @param request
     *            The request to sign.
     */
    public void sign(Request request, AWSCredentials credentials) throws AmazonClientException {
        // annonymous credentials, don't sign
        if ( credentials instanceof AnonymousAWSCredentials ) {
            return;
        }

        AWSCredentials sanitizedCredentials = sanitizeCredentials(credentials);

        SigningAlgorithm algorithm = SigningAlgorithm.HmacSHA256;
        String nonce = UUID.randomUUID().toString();

        int timeOffset = getTimeOffset(request);
        Date dateValue = getSignatureDate(timeOffset);
        String date = dateUtils.formatRfc822Date(dateValue);
        boolean isHttps = false;

        if (overriddenDate != null) date = overriddenDate;
        request.addHeader("Date", date);
        request.addHeader("X-Amz-Date", date);

        // AWS3 HTTP requires that we sign the Host header
        // so we have to have it in the request by the time we sign.
        String hostHeader = request.getEndpoint().getHost();
        if (HttpUtils.isUsingNonDefaultPort(request.getEndpoint())) {
            hostHeader += ":" + request.getEndpoint().getPort();
        }
        request.addHeader("Host", hostHeader);

        if ( sanitizedCredentials instanceof AWSSessionCredentials ) {
            addSessionCredentials(request, (AWSSessionCredentials) sanitizedCredentials);
        }
        byte[] bytesToSign;
        String stringToSign;
        if (isHttps) {
            request.addHeader(NONCE_HEADER, nonce);
            stringToSign = date + nonce;
            bytesToSign = stringToSign.getBytes(UTF8);
        } else {
            String path = HttpUtils.appendUri(request.getEndpoint().getPath(), request.getResourcePath());

            /*
             * AWS3 requires all query params to be listed on the third line of
             * the string to sign, even if those query params will be sent in
             * the request body and not as a query string. POST formatted query
             * params should *NOT* be included in the request payload.
             */
            stringToSign = request.getHttpMethod().toString() + "\n"
                    + getCanonicalizedResourcePath(path) + "\n"
                    + getCanonicalizedQueryString(request.getParameters()) + "\n"
                    + getCanonicalizedHeadersForStringToSign(request) + "\n"
                    + getRequestPayloadWithoutQueryParams(request);
            bytesToSign = hash(stringToSign);
        }
        log.debug("Calculated StringToSign: " + stringToSign);

        String signature = signAndBase64Encode(bytesToSign, sanitizedCredentials.getAWSSecretKey(), algorithm);

        StringBuilder builder = new StringBuilder();
        builder.append(isHttps ? HTTPS_SCHEME : HTTP_SCHEME).append(" ");
        builder.append("AWSAccessKeyId=" + sanitizedCredentials.getAWSAccessKeyId() + ",");
        builder.append("Algorithm=" + algorithm.toString() + ",");

        if (!isHttps) {
            builder.append(getSignedHeadersComponent(request) + ",");
        }

        builder.append("Signature=" + signature);
        request.addHeader(AUTHORIZATION_HEADER, builder.toString());
    }

    private String getSignedHeadersComponent(Request request) {
        StringBuilder builder = new StringBuilder();
        builder.append("SignedHeaders=");
        boolean first = true;
        for (String header : getHeadersForStringToSign(request)) {
            if (!first) builder.append(";");
            builder.append(header);
            first = false;
        }
        return builder.toString();
    }

    protected List getHeadersForStringToSign(Request request) {
        List headersToSign = new ArrayList();
        for (Map.Entry entry : request.getHeaders().entrySet()) {
            String key = entry.getKey();
            String lowerCaseKey = key.toLowerCase();
            if (lowerCaseKey.startsWith("x-amz")
                    || lowerCaseKey.equals("host")) {
                headersToSign.add(key);
            }
        }

        Collections.sort(headersToSign);
        return headersToSign;
    }

    /**
     * For internal testing only - allows the date to be overridden for internal
     * tests.
     *
     * @param date
     *            The RFC822 date string to use when signing requests.
     */
    void overrideDate(String date) {
        this.overriddenDate = date;
    }

    protected String getCanonicalizedHeadersForStringToSign(Request request) {
        List headersToSign = getHeadersForStringToSign(request);

        for (int i = 0; i < headersToSign.size(); i++) {
            headersToSign.set(i, headersToSign.get(i).toLowerCase());
        }

        SortedMap sortedHeaderMap = new TreeMap();
        for (Map.Entry entry : request.getHeaders().entrySet()) {
            if (headersToSign.contains(entry.getKey().toLowerCase())) {
                sortedHeaderMap.put(entry.getKey().toLowerCase(), entry.getValue());
            }
        }

        StringBuilder builder = new StringBuilder();
        for (Map.Entry entry : sortedHeaderMap.entrySet()) {
            builder.append(entry.getKey().toLowerCase()).append(":")
            .append(entry.getValue()).append("\n");
        }

        return builder.toString();
    }

    protected boolean shouldUseHttpsScheme(Request request) throws AmazonClientException {
        try {
            String protocol = request.getEndpoint().toURL().getProtocol().toLowerCase();
            if (protocol.equals("http")) {
                return false;
            } else if (protocol.equals("https")) {
                return true;
            } else {
                throw new AmazonClientException("Unknown request endpoint protocol " +
                        "encountered while signing request: " + protocol);
            }
        } catch (MalformedURLException e) {
            throw new AmazonClientException("Unable to parse request endpoint during signing", e);
        }
    }

    @Override
    protected void addSessionCredentials(Request request, AWSSessionCredentials credentials) {
        request.addHeader("x-amz-security-token", credentials.getSessionToken());
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy