0

I am working for Amazon S3 service and I have used jets3t for API. Actually its long time ago I have last used jets3t version was : 0.8.1, as now the new jets3t arrived with version : 0.9.6. I am using Java 7.

I am trying to connect with S3, but for few buckets (like Frankfurt) it throwing the issue of : The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256

I analyzed the changes made in new jets3t and want to merge into my existing old code, as of now I can not completely change the code of jets3t, I just want to resolve the authorization issue.

So I have updated authorizeHttpRequest request method with new changes as given below from latest github changes : https://github.com/mondain/jets3t/tree/master/jets3t:

public void authorizeHttpRequest(HttpMethod httpMethod, String forceRequestSignatureVersion) throws Exception {
        if (getProviderCredentials() != null) {
            if (log.isDebugEnabled()) {
                log.debug("Adding authorization for Access Key '"
                        + getProviderCredentials().getAccessKey() + "'.");
            }
        } else {
            if (log.isDebugEnabled()) {
                log.debug("Service has no Credential and is un-authenticated, skipping authorization");
            }
            return;
        }
// Clear any existing Authorization headers
        httpMethod.removeRequestHeader("Authorization");

        // Set/update the date timestamp to the current time
        // Note that this will be over-ridden if an "x-amz-date" or
        // "x-goog-date" header is present.
        httpMethod.setRequestHeader("Date",
                ServiceUtils.formatRfc822Date(getCurrentTimeWithOffset()));

        URI requestURI = null;
        if (httpMethod.getURI().isAbsoluteURI()) {
            requestURI = httpMethod.getURI();
        }
//        else {
//            // Handle strange edge-case that can occur when retrying requests in
//            // which the URI object has a null host value, re #205
//            try {
//                // Re-create request's URI to populate its internal host value
//                requestURI = new java.net.URI(String.format("%s%s",
//                        context.getAttribute(HttpCoreContext.HTTP_TARGET_HOST).toString(), httpMethod.getURI()));
//            } catch (URISyntaxException e) {
//                throw new ServiceException(
//                    "Failed to re-create URI for reHttpCoreContextquest containing a URI"
//                    + " object with an invalid null Host value", e);
//            }
//        }
        //String forceRequestSignatureVersion = null;

        String requestBucketName = ServiceUtils.findBucketNameInHostOrPath(
                new java.net.URI(requestURI.toString()), this.getEndpoint());
        String requestSignatureVersion = this.getJetS3tProperties()
                .getStringProperty(
                "storage-service.request-signature-version", "AWS2")
                .toUpperCase();

        if ("AWS4-HMAC-SHA256".equalsIgnoreCase(forceRequestSignatureVersion)
                || "AWS4-HMAC-SHA256".equalsIgnoreCase(requestSignatureVersion)
                // If we have a cached region for request's bucket target, we know
                // we have used "AWS4-HMAC-SHA256" for this bucket in the past.
                || (this.regionEndpointCache != null
                && this.regionEndpointCache.containsRegionForBucketName(
                requestBucketName))) {
            requestSignatureVersion = "AWS4-HMAC-SHA256";
            // Look up AWS region appropriate for the request's Host endpoint
            // from the request's Host if a definite mapping is available...
            String region = SignatureUtils.awsRegionForRequest(new java.net.URI(requestURI.toString()));
            if (region != null) {
                // Try caching the definitive region in case this request is
                // directed at a bucket. If it's not a bucket-related request
                // this is a no-op.
                this.regionEndpointCache.putRegionForBucketName(
                        requestBucketName, region);
            }
            // ...otherwise from the region cache if available...
            if (region == null && this.regionEndpointCache != null) {
                region = this.regionEndpointCache.getRegionForBucketName(
                        requestBucketName);

                // We cached a bucket-to-region mapping previously but this
                // request doesn't use the correct Host name for the region,
                // so fix that now to avoid failure or excess retries.
                java.net.URI newURI = new java.net.URI(requestURI.toString());
                org.apache.commons.httpclient.URI apacheURI = new org.apache.commons.httpclient.URI(SignatureUtils.awsV4CorrectHostnameForRegion(
                        newURI, region).toString());
                if (region != null) {
                    (httpMethod).setURI(apacheURI);
                }
            }
            // ...finally fall back to the default region and hope for the best.
            if (region == null) {
                region = "us-east-1";
            }


            String requestPayloadHexSHA256Hash =
                    SignatureUtils.awsV4GetOrCalculatePayloadHash(httpMethod);
            httpMethod.setRequestHeader(
                    "x-amz-content-sha256", requestPayloadHexSHA256Hash);

            SignatureUtils.awsV4SignRequestAuthorizationHeader(
                    requestSignatureVersion, httpMethod,
                    this.getProviderCredentials(), requestPayloadHexSHA256Hash,
                    region);
        } else if ("AWS2".equalsIgnoreCase(forceRequestSignatureVersion)
                || "AWS2".equalsIgnoreCase(requestSignatureVersion)) {
            /*
             * Determine the complete URL for the S3 resource, including any S3-specific parameters.
             */
            // Use raw-path, otherwise escaped characters are unescaped and a wrong
            // signature is produced
            String fullUrl = requestURI.getURI();

            // If bucket name is not already part of the full path, add it.
            // This can be the case if the Host name has a bucket-name prefix,
            // or if the Host name constitutes the bucket name for DNS-redirects.
            String bucketName = ServiceUtils.findBucketNameInHostOrPath(
                    new java.net.URI(requestURI.toString()), getEndpoint());
            if (bucketName != null && requestURI.getHost().startsWith(bucketName)) {
                fullUrl = "/" + bucketName + fullUrl;
            }

            String queryString = new java.net.URI(requestURI.toString()).getRawQuery();
            if (queryString != null && queryString.length() > 0) {
                fullUrl += "?" + queryString;
            }

            // Generate a canonical string representing the operation.
            String canonicalString = RestUtils.makeServiceCanonicalString(
                    httpMethod.getName(),
                    fullUrl,
                    convertHeadersToMap(httpMethod.getRequestHeaders()),
                    null,
                    getRestHeaderPrefix(),
                    getResourceParameterNames());
            if (log.isDebugEnabled()) {
                log.debug("Canonical string ('|' is a newline): " + canonicalString.replace('\n', '|'));
            }

            // Sign the canonical string.
            String signedCanonical = ServiceUtils.signWithHmacSha1(
                    getProviderCredentials().getSecretKey(), canonicalString);

            // Add encoded authorization to connection as HTTP Authorization header.
            String authorizationString = getSignatureIdentifier() + " "
                    + getProviderCredentials().getAccessKey() + ":" + signedCanonical;
            httpMethod.setRequestHeader("Authorization", authorizationString);
        } else {
            throw new ServiceException("Unsupported property setting for "
                    + "storage-service.request-signature-version \""
                    + requestSignatureVersion + "\", must be one of: "
                    + "\"AWS2\" (legacy), \"AWS4-HMAC-SHA256\"");
        }
    }

But now it throwing the new issue of : The request signature we calculated does not match the signature you provided. Check your key and signing method.

How can I resolve the authentication issue with jets3t ? There is option of AWS SDK also, but how two can manage together if I use AWS SDK for authentication?

Neelam Sharma
  • 2,745
  • 4
  • 32
  • 73

1 Answers1

0

Add the following your AWS settings:

AWS_S3_SIGNATURE_VERSION = 's3v4' AWS_S3_REGION_NAME = 'eu-west-3' # enter your REGION_NAME... which you can find on your bucket AWS specifications.

As AWS added a signature requirement to new buckets, the version variable allows to set it to v4. As for the Region variable. I noted that some report that in certain regions it made a difference (like India)... in case it helps.

donbonbon
  • 81
  • 1
  • 8