Beispiel #1
0
  /**
   * Converts the specified request object into a URL, containing all the specified parameters, the
   * specified request endpoint, etc.
   *
   * @param request The request to convert into a URL.
   * @param removeLeadingSlashInResourcePath Whether the leading slash in resource-path should be
   *     removed before appending to the endpoint.
   * @return A new URL representing the specified request.
   * @throws AmazonClientException If the request cannot be converted to a well formed URL.
   */
  public static URL convertRequestToUrl(
      Request<?> request, boolean removeLeadingSlashInResourcePath) {
    String resourcePath = HttpUtils.urlEncode(request.getResourcePath(), true);

    // Removed the padding "/" that was already added into the request's resource path.
    if (removeLeadingSlashInResourcePath && resourcePath.startsWith("/")) {
      resourcePath = resourcePath.substring(1);
    }

    // Some http client libraries (e.g. Apache HttpClient) cannot handle
    // consecutive "/"s between URL authority and path components.
    // So we escape "////..." into "/%2F%2F%2F...", in the same way as how
    // we treat consecutive "/"s in AmazonS3Client#presignRequest(...)
    String urlPath = "/" + resourcePath;
    urlPath = urlPath.replaceAll("(?<=/)/", "%2F");
    String urlString = request.getEndpoint() + urlPath;

    boolean firstParam = true;
    for (String param : request.getParameters().keySet()) {
      if (firstParam) {
        urlString += "?";
        firstParam = false;
      } else {
        urlString += "&";
      }

      String value = request.getParameters().get(param);
      urlString += param + "=" + HttpUtils.urlEncode(value, false);
    }

    try {
      return new URL(urlString);
    } catch (MalformedURLException e) {
      throw new AmazonClientException(
          "Unable to convert request to well formed URL: " + e.getMessage(), e);
    }
  }
  /* (non-Javadoc)
   * @see com.amazonaws.auth.Signer#sign(com.amazonaws.Request, com.amazonaws.auth.AWSCredentials)
   */
  public void sign(Request<?> request, AWSCredentials credentials) throws AmazonClientException {
    // annonymous credentials, don't sign
    if (credentials instanceof AnonymousAWSCredentials) {
      return;
    }

    AWSCredentials sanitizedCredentials = sanitizeCredentials(credentials);
    if (sanitizedCredentials instanceof AWSSessionCredentials) {
      addSessionCredentials(request, (AWSSessionCredentials) sanitizedCredentials);
    }

    SimpleDateFormat dateStampFormat = new SimpleDateFormat("yyyyMMdd");
    dateStampFormat.setTimeZone(new SimpleTimeZone(0, "UTC"));

    SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
    dateTimeFormat.setTimeZone(new SimpleTimeZone(0, "UTC"));

    String regionName = extractRegionName(request.getEndpoint());
    String serviceName = extractServiceName(request.getEndpoint());

    // AWS4 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);

    Date date = new Date();
    if (overriddenDate != null) date = overriddenDate;

    String dateTime = dateTimeFormat.format(date);
    String dateStamp = dateStampFormat.format(date);

    InputStream payloadStream = getBinaryRequestPayloadStream(request);
    payloadStream.mark(-1);
    String contentSha256 = BinaryUtils.toHex(hash(payloadStream));
    try {
      payloadStream.reset();
    } catch (IOException e) {
      throw new AmazonClientException("Unable to reset stream after calculating AWS4 signature", e);
    }

    request.addHeader("X-Amz-Date", dateTime);
    request.addHeader("x-amz-content-sha256", contentSha256);

    String canonicalRequest =
        request.getHttpMethod().toString()
            + "\n"
            + super.getCanonicalizedResourcePath(request.getResourcePath())
            + "\n"
            + getCanonicalizedQueryString(request)
            + "\n"
            + getCanonicalizedHeaderString(request)
            + "\n"
            + getSignedHeadersString(request)
            + "\n"
            + contentSha256;

    log.debug("AWS4 Canonical Request: '\"" + canonicalRequest + "\"");

    String scope = dateStamp + "/" + regionName + "/" + serviceName + "/" + TERMINATOR;
    String signingCredentials = sanitizedCredentials.getAWSAccessKeyId() + "/" + scope;
    String stringToSign =
        ALGORITHM
            + "\n"
            + dateTime
            + "\n"
            + scope
            + "\n"
            + BinaryUtils.toHex(hash(canonicalRequest));
    log.debug("AWS4 String to Sign: '\"" + stringToSign + "\"");

    // AWS4 uses a series of derived keys, formed by hashing different pieces of data
    byte[] kSecret = ("AWS4" + sanitizedCredentials.getAWSSecretKey()).getBytes();
    byte[] kDate = sign(dateStamp, kSecret, SigningAlgorithm.HmacSHA256);
    byte[] kRegion = sign(regionName, kDate, SigningAlgorithm.HmacSHA256);
    byte[] kService = sign(serviceName, kRegion, SigningAlgorithm.HmacSHA256);
    byte[] kSigning = sign(TERMINATOR, kService, SigningAlgorithm.HmacSHA256);

    byte[] signature = sign(stringToSign.getBytes(), kSigning, SigningAlgorithm.HmacSHA256);

    String credentialsAuthorizationHeader = "Credential=" + signingCredentials;
    String signedHeadersAuthorizationHeader = "SignedHeaders=" + getSignedHeadersString(request);
    String signatureAuthorizationHeader = "Signature=" + BinaryUtils.toHex(signature);

    String authorizationHeader =
        ALGORITHM
            + " "
            + credentialsAuthorizationHeader
            + ", "
            + signedHeadersAuthorizationHeader
            + ", "
            + signatureAuthorizationHeader;

    request.addHeader("Authorization", authorizationHeader);
  }