You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ga...@apache.org on 2013/07/25 00:23:20 UTC
git commit: AWS-S3 configurable temporary signed URL support
Updated Branches:
refs/heads/master 48b499c63 -> c64c7423c
AWS-S3 configurable temporary signed URL support
Introduces AWSS3BlobRequestSigner, which reuses the
RequestAuthorizeSignature filter for most of the heavy lifting.
Other implementation details based on [1].
Tested with AWSS3BlobSignerLiveTest, in particular,
testSign(Get|Put)UrlWithTime.
Closes JCLOUDS-200
[1] http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
Project: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/commit/c64c7423
Tree: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/tree/c64c7423
Diff: http://git-wip-us.apache.org/repos/asf/incubator-jclouds/diff/c64c7423
Branch: refs/heads/master
Commit: c64c7423cdc2dac13d34196f7d526ba364c745c0
Parents: 48b499c
Author: Diwaker Gupta <di...@maginatics.com>
Authored: Mon Jul 22 09:30:22 2013 -0700
Committer: Andrew Gaul <ga...@apache.org>
Committed: Wed Jul 24 15:22:45 2013 -0700
----------------------------------------------------------------------
.../s3/blobstore/S3BlobRequestSigner.java | 12 +--
.../s3/filters/RequestAuthorizeSignature.java | 8 ++
.../s3/blobstore/AWSS3BlobRequestSigner.java | 98 ++++++++++++++++++++
.../config/AWSS3BlobStoreContextModule.java | 7 +-
.../s3/blobstore/AWSS3BlobSignerExpectTest.java | 92 ++++++++++++++++++
.../integration/AWSS3BlobSignerLiveTest.java | 11 +++
6 files changed, 217 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c64c7423/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java
----------------------------------------------------------------------
diff --git a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java
index 9162f75..d6402af 100644
--- a/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java
+++ b/apis/s3/src/main/java/org/jclouds/s3/blobstore/S3BlobRequestSigner.java
@@ -44,13 +44,13 @@ import com.google.common.reflect.Invokable;
*/
@Singleton
public class S3BlobRequestSigner<T extends S3AsyncClient> implements BlobRequestSigner {
- private final RestAnnotationProcessor processor;
- private final BlobToObject blobToObject;
- private final BlobToHttpGetOptions blob2HttpGetOptions;
+ protected final RestAnnotationProcessor processor;
+ protected final BlobToObject blobToObject;
+ protected final BlobToHttpGetOptions blob2HttpGetOptions;
- private final Invokable<?, ?> getMethod;
- private final Invokable<?, ?> deleteMethod;
- private final Invokable<?, ?> createMethod;
+ protected final Invokable<?, ?> getMethod;
+ protected final Invokable<?, ?> deleteMethod;
+ protected final Invokable<?, ?> createMethod;
@Inject
public S3BlobRequestSigner(RestAnnotationProcessor processor, BlobToObject blobToObject,
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c64c7423/apis/s3/src/main/java/org/jclouds/s3/filters/RequestAuthorizeSignature.java
----------------------------------------------------------------------
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 885b2ee..ca85401 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,6 +50,7 @@ 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,6 +134,13 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
}
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()
.replaceHeader(HttpHeaders.AUTHORIZATION, authTag + " " + creds.get().identity + ":" + signature).build();
return request;
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c64c7423/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobRequestSigner.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..b0b9824
--- /dev/null
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/AWSS3BlobRequestSigner.java
@@ -0,0 +1,98 @@
+/*
+ * 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.blobstore;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
+
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+import org.jclouds.aws.s3.AWSS3AsyncClient;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
+import org.jclouds.date.DateService;
+import org.jclouds.date.TimeStamp;
+import org.jclouds.domain.Credentials;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.reflect.Invocation;
+import org.jclouds.rest.internal.RestAnnotationProcessor;
+import org.jclouds.s3.blobstore.S3BlobRequestSigner;
+import org.jclouds.s3.blobstore.functions.BlobToObject;
+import org.jclouds.s3.filters.RequestAuthorizeSignature;
+
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+import com.google.common.net.HttpHeaders;
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+
+/**
+ * @author Diwaker Gupta
+ */
+public class AWSS3BlobRequestSigner extends S3BlobRequestSigner<AWSS3AsyncClient> {
+ private final RequestAuthorizeSignature authSigner;
+ private final String identity;
+ private final DateService dateService;
+ private final Provider<String> timeStampProvider;
+
+ @Inject
+ public AWSS3BlobRequestSigner(RestAnnotationProcessor processor, BlobToObject blobToObject,
+ BlobToHttpGetOptions blob2HttpGetOptions, Class<AWSS3AsyncClient> interfaceClass,
+ @org.jclouds.location.Provider Supplier<Credentials> credentials,
+ RequestAuthorizeSignature authSigner, @TimeStamp Provider<String> timeStampProvider,
+ DateService dateService) throws SecurityException, NoSuchMethodException {
+ super(processor, blobToObject, blob2HttpGetOptions, interfaceClass);
+ this.authSigner = authSigner;
+ this.identity = credentials.get().identity;
+ this.dateService = dateService;
+ this.timeStampProvider = timeStampProvider;
+ }
+
+ @Override
+ public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
+ checkNotNull(container, "container");
+ checkNotNull(name, "name");
+ HttpRequest request = processor.apply(Invocation.create(getMethod, ImmutableList.<Object> of(container, name)));
+ return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
+ }
+
+ @Override
+ public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
+ checkNotNull(container, "container");
+ checkNotNull(blob, "blob");
+ HttpRequest request = processor.apply(Invocation.create(createMethod,
+ ImmutableList.<Object>of(container, blobToObject.apply(blob))));
+ return cleanRequest(signForTemporaryAccess(request, timeInSeconds));
+ }
+
+ private HttpRequest signForTemporaryAccess(HttpRequest request, long timeInSeconds) {
+ // Update the 'DATE' header
+ String dateString = request.getFirstHeaderOrNull(HttpHeaders.DATE);
+ if (dateString == null) {
+ dateString = timeStampProvider.get();
+ }
+ Date date = dateService.rfc1123DateParse(dateString);
+ String expiration = String.valueOf(TimeUnit.MILLISECONDS.toSeconds(date.getTime()) + timeInSeconds);
+ HttpRequest.Builder<?> builder = request.toBuilder().replaceHeader(HttpHeaders.DATE, expiration);
+ final String signature = authSigner.sign(authSigner.createStringToSign(builder.build()));
+ return builder.addQueryParam("Signature", signature)
+ .addQueryParam(HttpHeaders.EXPIRES, expiration)
+ .addQueryParam("AWSAccessKeyId", identity)
+ .build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c64c7423/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java
----------------------------------------------------------------------
diff --git a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java
index cb454bb..501645c 100644
--- a/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java
+++ b/providers/aws-s3/src/main/java/org/jclouds/aws/s3/blobstore/config/AWSS3BlobStoreContextModule.java
@@ -16,8 +16,8 @@
*/
package org.jclouds.aws.s3.blobstore.config;
-import org.jclouds.aws.s3.AWSS3AsyncClient;
import org.jclouds.aws.s3.blobstore.AWSS3AsyncBlobStore;
+import org.jclouds.aws.s3.blobstore.AWSS3BlobRequestSigner;
import org.jclouds.aws.s3.blobstore.AWSS3BlobStore;
import org.jclouds.aws.s3.blobstore.strategy.AsyncMultipartUploadStrategy;
import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy;
@@ -25,12 +25,10 @@ import org.jclouds.aws.s3.blobstore.strategy.internal.ParallelMultipartUploadStr
import org.jclouds.aws.s3.blobstore.strategy.internal.SequentialMultipartUploadStrategy;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.s3.blobstore.S3AsyncBlobStore;
-import org.jclouds.s3.blobstore.S3BlobRequestSigner;
import org.jclouds.s3.blobstore.S3BlobStore;
import org.jclouds.s3.blobstore.config.S3BlobStoreContextModule;
import com.google.inject.Scopes;
-import com.google.inject.TypeLiteral;
/**
*
@@ -50,7 +48,6 @@ public class AWSS3BlobStoreContextModule extends S3BlobStoreContextModule {
@Override
protected void bindRequestSigner() {
- bind(BlobRequestSigner.class).to(new TypeLiteral<S3BlobRequestSigner<AWSS3AsyncClient>>() {
- });
+ bind(BlobRequestSigner.class).to(AWSS3BlobRequestSigner.class);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c64c7423/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/AWSS3BlobSignerExpectTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/AWSS3BlobSignerExpectTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/AWSS3BlobSignerExpectTest.java
new file mode 100644
index 0000000..d041abd
--- /dev/null
+++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/AWSS3BlobSignerExpectTest.java
@@ -0,0 +1,92 @@
+/*
+ * 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.blobstore;
+
+import static org.testng.Assert.assertEquals;
+
+import org.jclouds.aws.s3.config.AWSS3RestClientModule;
+import org.jclouds.blobstore.BlobStore;
+import org.jclouds.blobstore.domain.Blob;
+import org.jclouds.date.TimeStamp;
+import org.jclouds.http.HttpRequest;
+import org.jclouds.rest.ConfiguresRestClient;
+import org.jclouds.s3.blobstore.S3BlobSignerExpectTest;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Supplier;
+import com.google.inject.Module;
+
+/**
+ * @author Diwaker Gupta
+ */
+@Test(groups = "unit", testName = "AWSS3BlobSignerExpectTest")
+public class AWSS3BlobSignerExpectTest extends S3BlobSignerExpectTest {
+ public AWSS3BlobSignerExpectTest() {
+ provider = "aws-s3";
+ }
+
+ @Override
+ protected HttpRequest getBlobWithTime() {
+ return HttpRequest.builder().method("GET")
+ .endpoint("https://container.s3.amazonaws.com/name" +
+ "?Signature=Y4Ac4sZfBemGZmgfG78F7IX%20IFg%3D&Expires=1212683902&AWSAccessKeyId=identity")
+ .addHeader("Host", "container.s3.amazonaws.com")
+ .addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT").build();
+ }
+
+ @Test
+ public void testSignGetBlobWithTime() {
+ BlobStore getBlobWithTime = requestsSendResponses(init());
+ HttpRequest compare = getBlobWithTime();
+ assertEquals(getBlobWithTime.getContext().getSigner().signGetBlob(container, name, 3l /* seconds */),
+ compare);
+ }
+
+ @Override
+ protected HttpRequest putBlobWithTime() {
+ return HttpRequest.builder().method("PUT")
+ .endpoint("https://container.s3.amazonaws.com/name" +
+ "?Signature=genkB2vLxe3AWV/bPvRTMqQts7E%3D&Expires=1212683902&AWSAccessKeyId=identity")
+ .addHeader("Expect", "100-continue")
+ .addHeader("Host", "container.s3.amazonaws.com")
+ .addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT").build();
+ }
+
+ @Test
+ public void testSignPutBlobWithTime() throws Exception {
+ BlobStore signPutBloblWithTime = requestsSendResponses(init());
+ Blob blob = signPutBloblWithTime.blobBuilder(name).payload(text).contentType("text/plain").build();
+ HttpRequest compare = putBlobWithTime();
+ compare.setPayload(blob.getPayload());
+ assertEquals(signPutBloblWithTime.getContext().getSigner().signPutBlob(container, blob, 3l /* seconds */),
+ compare);
+ }
+
+ @Override
+ protected Module createModule() {
+ return new TestAWSS3RestClientModule();
+ }
+
+ @ConfiguresRestClient
+ private static final class TestAWSS3RestClientModule extends AWSS3RestClientModule {
+ @Override
+ @TimeStamp
+ protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
+ return "Thu, 05 Jun 2008 16:38:19 GMT";
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-jclouds/blob/c64c7423/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/integration/AWSS3BlobSignerLiveTest.java
----------------------------------------------------------------------
diff --git a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/integration/AWSS3BlobSignerLiveTest.java b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/integration/AWSS3BlobSignerLiveTest.java
index d0f86f6..0a3ec91 100644
--- a/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/integration/AWSS3BlobSignerLiveTest.java
+++ b/providers/aws-s3/src/test/java/org/jclouds/aws/s3/blobstore/integration/AWSS3BlobSignerLiveTest.java
@@ -16,6 +16,9 @@
*/
package org.jclouds.aws.s3.blobstore.integration;
+import java.util.Properties;
+
+import org.jclouds.Constants;
import org.jclouds.s3.blobstore.integration.S3BlobSignerLiveTest;
import org.testng.annotations.Test;
@@ -28,4 +31,12 @@ public class AWSS3BlobSignerLiveTest extends S3BlobSignerLiveTest {
public AWSS3BlobSignerLiveTest() {
provider = "aws-s3";
}
+
+ @Override
+ protected Properties setupProperties() {
+ Properties overrides = super.setupProperties();
+ overrides.setProperty(Constants.PROPERTY_STRIP_EXPECT_HEADER, "true");
+ overrides.setProperty(Constants.PROPERTY_SESSION_INTERVAL, "1");
+ return overrides;
+ }
}