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?