JCLOUDS-200: Consolidate all feature-specific in the AWS provider

Follow-up to c64c7423
This commit is contained in:
Andrew Phillips 2013-07-26 15:03:12 -04:00
parent 2409ac1a37
commit f6b5b67b5b
7 changed files with 124 additions and 12 deletions

View File

@ -162,7 +162,7 @@ public class S3RestClientModule<S extends S3Client, A extends S3AsyncClient> ext
super.configure(); super.configure();
install(new S3ObjectModule()); install(new S3ObjectModule());
install(new S3ParserModule()); install(new S3ParserModule());
bind(RequestAuthorizeSignature.class).in(Scopes.SINGLETON); bindRequestSigner();
bind(new TypeLiteral<Function<String, Optional<String>>>() { bind(new TypeLiteral<Function<String, Optional<String>>>() {
}).annotatedWith(Bucket.class).to(GetRegionForBucket.class); }).annotatedWith(Bucket.class).to(GetRegionForBucket.class);
bind(new TypeLiteral<Function<Set<BucketMetadata>, PageSet<? extends StorageMetadata>>>() { bind(new TypeLiteral<Function<Set<BucketMetadata>, PageSet<? extends StorageMetadata>>>() {
@ -176,6 +176,10 @@ public class S3RestClientModule<S extends S3Client, A extends S3AsyncClient> ext
bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseS3ErrorFromXmlContent.class); bind(HttpErrorHandler.class).annotatedWith(ServerError.class).to(ParseS3ErrorFromXmlContent.class);
} }
protected void bindRequestSigner() {
bind(RequestAuthorizeSignature.class).in(Scopes.SINGLETON);
}
@Provides @Provides
@Singleton @Singleton
protected RequestSigner provideRequestSigner(RequestAuthorizeSignature in) { protected RequestSigner provideRequestSigner(RequestAuthorizeSignature in) {

View File

@ -50,7 +50,6 @@ import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter; import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils; import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire; import org.jclouds.http.internal.SignatureWire;
import org.jclouds.http.utils.Queries;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.RequestSigner; import org.jclouds.rest.RequestSigner;
import org.jclouds.s3.util.S3Utils; 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(); return request.toBuilder().replaceHeader("x-amz-security-token", current.getSessionToken()).build();
} }
HttpRequest replaceAuthorizationHeader(HttpRequest request, String signature) { 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 (Queries.queryParser().apply(request.getEndpoint().getQuery()).containsKey("Signature")) {
return request;
}
request = request.toBuilder() request = request.toBuilder()
.replaceHeader(HttpHeaders.AUTHORIZATION, authTag + " " + creds.get().identity + ":" + signature).build(); .replaceHeader(HttpHeaders.AUTHORIZATION, authTag + " " + creds.get().identity + ":" + signature).build();
return request; return request;

View File

@ -45,6 +45,8 @@ import com.google.inject.Provider;
* @author Diwaker Gupta * @author Diwaker Gupta
*/ */
public class AWSS3BlobRequestSigner extends S3BlobRequestSigner<AWSS3AsyncClient> { public class AWSS3BlobRequestSigner extends S3BlobRequestSigner<AWSS3AsyncClient> {
public static final String TEMPORARY_SIGNATURE_PARAM = "Signature";
private final RequestAuthorizeSignature authSigner; private final RequestAuthorizeSignature authSigner;
private final String identity; private final String identity;
private final DateService dateService; private final DateService dateService;
@ -90,7 +92,7 @@ public class AWSS3BlobRequestSigner extends S3BlobRequestSigner<AWSS3AsyncClient
String expiration = String.valueOf(TimeUnit.MILLISECONDS.toSeconds(date.getTime()) + timeInSeconds); String expiration = String.valueOf(TimeUnit.MILLISECONDS.toSeconds(date.getTime()) + timeInSeconds);
HttpRequest.Builder<?> builder = request.toBuilder().replaceHeader(HttpHeaders.DATE, expiration); HttpRequest.Builder<?> builder = request.toBuilder().replaceHeader(HttpHeaders.DATE, expiration);
final String signature = authSigner.sign(authSigner.createStringToSign(builder.build())); 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(HttpHeaders.EXPIRES, expiration)
.addQueryParam("AWSAccessKeyId", identity) .addQueryParam("AWSAccessKeyId", identity)
.build(); .build();

View File

@ -23,17 +23,20 @@ import javax.inject.Singleton;
import org.jclouds.aws.s3.AWSS3AsyncClient; import org.jclouds.aws.s3.AWSS3AsyncClient;
import org.jclouds.aws.s3.AWSS3Client; import org.jclouds.aws.s3.AWSS3Client;
import org.jclouds.aws.s3.filters.AWSRequestAuthorizeSignature;
import org.jclouds.aws.s3.predicates.validators.AWSS3BucketNameValidator; import org.jclouds.aws.s3.predicates.validators.AWSS3BucketNameValidator;
import org.jclouds.location.Region; import org.jclouds.location.Region;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.s3.S3AsyncClient; import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client; import org.jclouds.s3.S3Client;
import org.jclouds.s3.config.S3RestClientModule; import org.jclouds.s3.config.S3RestClientModule;
import org.jclouds.s3.filters.RequestAuthorizeSignature;
import org.jclouds.s3.predicates.validators.BucketNameValidator; import org.jclouds.s3.predicates.validators.BucketNameValidator;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.inject.Provides; import com.google.inject.Provides;
import com.google.inject.Scopes;
/** /**
* Configures the S3 connection. * Configures the S3 connection.
@ -58,6 +61,11 @@ public class AWSS3RestClientModule extends S3RestClientModule<AWSS3Client, AWSS3
super.configure(); super.configure();
} }
@Override
protected void bindRequestSigner() {
bind(RequestAuthorizeSignature.class).to(AWSRequestAuthorizeSignature.class).in(Scopes.SINGLETON);
}
@Singleton @Singleton
@Provides @Provides
S3Client provide(AWSS3Client in) { S3Client provide(AWSS3Client in) {

View File

@ -0,0 +1,75 @@
/*
* 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.
*/
package org.jclouds.aws.s3.filters;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.aws.s3.blobstore.AWSS3BlobRequestSigner.TEMPORARY_SIGNATURE_PARAM;
import static org.jclouds.http.utils.Queries.queryParser;
import static org.jclouds.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH;
import static org.jclouds.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.TimeStamp;
import org.jclouds.domain.Credentials;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire;
import org.jclouds.s3.filters.RequestAuthorizeSignature;
import com.google.common.base.Supplier;
/**
* Signs the AWS S3 request, supporting temporary signatures.
*
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonS3/2006-03-01/dev/index.html?RESTAuthentication.html"
* />
*
*/
@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<Credentials> creds,
@TimeStamp Provider<String> 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);
}
}

View File

@ -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 <a href="http://docs.amazonwebservices.com/AmazonS3/latest/RESTAuthentication.html" />
* @author Adrian Cole
*/
package org.jclouds.aws.s3.filters;

View File

@ -17,6 +17,7 @@
package org.jclouds.aws.s3; package org.jclouds.aws.s3;
import static org.jclouds.reflect.Reflection2.method; import static org.jclouds.reflect.Reflection2.method;
import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -24,11 +25,13 @@ import java.util.Set;
import org.jclouds.Fallbacks.VoidOnNotFoundOr404; import org.jclouds.Fallbacks.VoidOnNotFoundOr404;
import org.jclouds.aws.s3.config.AWSS3RestClientModule; 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.ETagFromHttpResponseViaRegex;
import org.jclouds.aws.s3.functions.UploadIdFromHttpResponseViaRegex; import org.jclouds.aws.s3.functions.UploadIdFromHttpResponseViaRegex;
import org.jclouds.blobstore.binders.BindBlobToMultipartFormTest; import org.jclouds.blobstore.binders.BindBlobToMultipartFormTest;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions; import org.jclouds.fallbacks.MapHttp4xxCodesToExceptions;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseETagHeader; import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReleasePayloadAndReturn; import org.jclouds.http.functions.ReleasePayloadAndReturn;
@ -68,6 +71,12 @@ import com.google.inject.Module;
@Test(groups = "unit", testName = "AWSS3AsyncClientTest") @Test(groups = "unit", testName = "AWSS3AsyncClientTest")
public class AWSS3AsyncClientTest extends S3AsyncClientTest<AWSS3AsyncClient> { public class AWSS3AsyncClientTest extends S3AsyncClientTest<AWSS3AsyncClient> {
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), AWSRequestAuthorizeSignature.class);
}
@Override @Override
public void testCopyObjectInvalidName() throws ArrayIndexOutOfBoundsException, SecurityException, public void testCopyObjectInvalidName() throws ArrayIndexOutOfBoundsException, SecurityException,
IllegalArgumentException, NoSuchMethodException, IOException { IllegalArgumentException, NoSuchMethodException, IOException {