diff --git a/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java b/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java index 33ac2ef2c7..cd71828a9d 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java +++ b/apis/s3/src/main/java/org/jclouds/s3/config/S3RestClientModule.java @@ -162,7 +162,7 @@ public class S3RestClientModule ext super.configure(); install(new S3ObjectModule()); install(new S3ParserModule()); - bind(RequestAuthorizeSignature.class).in(Scopes.SINGLETON); + bindRequestSigner(); bind(new TypeLiteral>>() { }).annotatedWith(Bucket.class).to(GetRegionForBucket.class); bind(new TypeLiteral, PageSet>>() { @@ -176,6 +176,10 @@ public class S3RestClientModule ext bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseS3ErrorFromXmlContent.class); } + protected void bindRequestSigner() { + bind(RequestAuthorizeSignature.class).in(Scopes.SINGLETON); + } + @Provides @Singleton protected RequestSigner provideRequestSigner(RequestAuthorizeSignature in) { diff --git a/apis/s3/src/main/java/org/jclouds/s3/filters/RequestAuthorizeSignature.java b/apis/s3/src/main/java/org/jclouds/s3/filters/RequestAuthorizeSignature.java index ca85401f6c..26e06b03de 100644 --- a/apis/s3/src/main/java/org/jclouds/s3/filters/RequestAuthorizeSignature.java +++ b/apis/s3/src/main/java/org/jclouds/s3/filters/RequestAuthorizeSignature.java @@ -50,7 +50,6 @@ import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpUtils; import org.jclouds.http.internal.SignatureWire; -import org.jclouds.http.utils.Queries; import org.jclouds.logging.Logger; import org.jclouds.rest.RequestSigner; import org.jclouds.s3.util.S3Utils; @@ -133,14 +132,7 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign return request.toBuilder().replaceHeader("x-amz-security-token", current.getSessionToken()).build(); } - HttpRequest replaceAuthorizationHeader(HttpRequest request, String signature) { - // Only add the Authorization header if the query string doesn't already contain - // the 'Signature' parameter, otherwise S3 will fail the request complaining about - // duplicate authentication methods. The 'Signature' parameter will be added for signed URLs - // with expiration. - if (Queries.queryParser().apply(request.getEndpoint().getQuery()).containsKey("Signature")) { - return request; - } + protected HttpRequest replaceAuthorizationHeader(HttpRequest request, String signature) { request = request.toBuilder() .replaceHeader(HttpHeaders.AUTHORIZATION, authTag + " " + creds.get().identity + ":" + signature).build(); return request; diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobRequestSigner.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobRequestSigner.java index b0b98241bf..775cdf5784 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobRequestSigner.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobRequestSigner.java @@ -45,6 +45,8 @@ import com.google.inject.Provider; * @author Diwaker Gupta */ public class AWSS3BlobRequestSigner extends S3BlobRequestSigner { + public static final String TEMPORARY_SIGNATURE_PARAM = "Signature"; + private final RequestAuthorizeSignature authSigner; private final String identity; private final DateService dateService; @@ -90,7 +92,7 @@ public class AWSS3BlobRequestSigner extends S3BlobRequestSigner builder = request.toBuilder().replaceHeader(HttpHeaders.DATE, expiration); final String signature = authSigner.sign(authSigner.createStringToSign(builder.build())); - return builder.addQueryParam("Signature", signature) + return builder.addQueryParam(TEMPORARY_SIGNATURE_PARAM, signature) .addQueryParam(HttpHeaders.EXPIRES, expiration) .addQueryParam("AWSAccessKeyId", identity) .build(); diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java index 6e8da5be21..3001a0e040 100644 --- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/config/AWSS3RestClientModule.java @@ -23,17 +23,20 @@ import javax.inject.Singleton; import org.jclouds.aws.s3.AWSS3AsyncClient; import org.jclouds.aws.s3.AWSS3Client; +import org.jclouds.aws.s3.filters.AWSRequestAuthorizeSignature; import org.jclouds.aws.s3.predicates.validators.AWSS3BucketNameValidator; import org.jclouds.location.Region; import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.s3.S3AsyncClient; import org.jclouds.s3.S3Client; import org.jclouds.s3.config.S3RestClientModule; +import org.jclouds.s3.filters.RequestAuthorizeSignature; import org.jclouds.s3.predicates.validators.BucketNameValidator; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.inject.Provides; +import com.google.inject.Scopes; /** * Configures the S3 connection. @@ -57,7 +60,12 @@ public class AWSS3RestClientModule extends S3RestClientModule + * + */ +@Singleton +public class AWSRequestAuthorizeSignature extends RequestAuthorizeSignature { + + @Inject + public AWSRequestAuthorizeSignature(SignatureWire signatureWire, @Named(PROPERTY_AUTH_TAG) String authTag, + @Named(PROPERTY_S3_VIRTUAL_HOST_BUCKETS) boolean isVhostStyle, + @Named(PROPERTY_S3_SERVICE_PATH) String servicePath, @Named(PROPERTY_HEADER_TAG) String headerTag, + @org.jclouds.location.Provider Supplier creds, + @TimeStamp Provider timeStampProvider, Crypto crypto, HttpUtils utils) { + super(signatureWire, authTag, isVhostStyle, servicePath, headerTag, creds, timeStampProvider, crypto, + utils); + } + + @Override + protected HttpRequest replaceAuthorizationHeader(HttpRequest request, String signature) { + /* + * Only add the Authorization header if the query string doesn't already contain + * the 'Signature' parameter, otherwise S3 will fail the request complaining about + * duplicate authentication methods. The 'Signature' parameter will be added for signed URLs + * with expiration. + */ + if (queryParser().apply(request.getEndpoint().getQuery()).containsKey(TEMPORARY_SIGNATURE_PARAM)) { + return request; + } + return super.replaceAuthorizationHeader(request, signature); + } +} diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/filters/package-info.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/filters/package-info.java new file mode 100644 index 0000000000..18c08ccda7 --- /dev/null +++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/filters/package-info.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License 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. + */ +/** + * This package contains HttpRequestFilters needed to operate the REST api. + * @see + * @author Adrian Cole + */ +package org.jclouds.aws.s3.filters; diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3AsyncClientTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3AsyncClientTest.java index e3f87935ed..5e940dd200 100644 --- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3AsyncClientTest.java +++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/AWSS3AsyncClientTest.java @@ -17,6 +17,7 @@ package org.jclouds.aws.s3; import static org.jclouds.reflect.Reflection2.method; +import static org.testng.Assert.assertEquals; import java.io.IOException; import java.util.Map; @@ -24,11 +25,13 @@ import java.util.Set; import org.jclouds.Fallbacks.VoidOnNotFoundOr404; import org.jclouds.aws.s3.config.AWSS3RestClientModule; +import org.jclouds.aws.s3.filters.AWSRequestAuthorizeSignature; import org.jclouds.aws.s3.functions.ETagFromHttpResponseViaRegex; import org.jclouds.aws.s3.functions.UploadIdFromHttpResponseViaRegex; import org.jclouds.blobstore.binders.BindBlobToMultipartFormTest; import org.jclouds.date.TimeStamp; import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions; +import org.jclouds.http.HttpRequest; import org.jclouds.http.functions.ParseETagHeader; import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ReleasePayloadAndReturn; @@ -68,6 +71,12 @@ import com.google.inject.Module; @Test(groups = "unit", testName = "AWSS3AsyncClientTest") public class AWSS3AsyncClientTest extends S3AsyncClientTest { + @Override + protected void checkFilters(HttpRequest request) { + assertEquals(request.getFilters().size(), 1); + assertEquals(request.getFilters().get(0).getClass(), AWSRequestAuthorizeSignature.class); + } + @Override public void testCopyObjectInvalidName() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException, NoSuchMethodException, IOException {