我正在为 Amazon S3 服务工作,并且我已将 jets3t 用于 API。其实很久以前我上次使用的jets3t版本是:0.8.1,现在新的jets3t版本是:0.9.6。我正在使用 Java 7。
我正在尝试与 S3 连接,但对于少数存储桶(如法兰克福),它会引发以下问题: 不支持您提供的授权机制。请使用 AWS4-HMAC-SHA256
我分析了新jets3t所做的更改,并想合并到我现有的旧代码中,目前我无法完全更改jets3t的代码,我只想解决授权问题。
因此,我更新了authorizeHttpRequest请求方法,其中包含最新的 github 更改,如下所示: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\"");
}
}
但是现在它抛出了新的问题:我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。
如何解决 jets3t 的身份验证问题?也有 AWS SDK 的选项,但是如果我使用 AWS SDK 进行身份验证,两者如何一起管理?