corrected guice bindings for swift-based blob signatures and backfilled expect tests

This commit is contained in:
Adrian Cole 2012-10-10 12:03:23 +02:00
parent 99d3422b4d
commit ffa9cd3bb0
32 changed files with 1140 additions and 550 deletions

View File

@ -22,15 +22,19 @@ import java.net.URI;
import java.util.Properties; import java.util.Properties;
import org.jclouds.apis.ApiMetadata; import org.jclouds.apis.ApiMetadata;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule; import org.jclouds.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule;
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule; import org.jclouds.cloudfiles.config.CloudFilesRestClientModule;
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule.StorageAndCDNManagementEndpointModule; import org.jclouds.cloudfiles.config.CloudFilesRestClientModule.StorageAndCDNManagementEndpointModule;
import org.jclouds.openstack.swift.SwiftApiMetadata; import org.jclouds.openstack.swift.SwiftApiMetadata;
import org.jclouds.openstack.swift.blobstore.SwiftBlobSigner;
import org.jclouds.openstack.swift.blobstore.config.TemporaryUrlExtensionModule;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/** /**
* Implementation of {@link ApiMetadata} for Rackspace Cloud Files API * Implementation of {@link ApiMetadata} for Rackspace Cloud Files API
@ -78,7 +82,11 @@ public class CloudFilesApiMetadata extends SwiftApiMetadata {
.documentation(URI.create("http://docs.rackspacecloud.com/files/api/v1/cfdevguide_d5/content/ch01.html")) .documentation(URI.create("http://docs.rackspacecloud.com/files/api/v1/cfdevguide_d5/content/ch01.html"))
.defaultProperties(CloudFilesApiMetadata.defaultProperties()) .defaultProperties(CloudFilesApiMetadata.defaultProperties())
.context(CONTEXT_TOKEN) .context(CONTEXT_TOKEN)
.defaultModules(ImmutableSet.<Class<? extends Module>>of(StorageAndCDNManagementEndpointModule.class, CloudFilesRestClientModule.class, CloudFilesBlobStoreContextModule.class)); .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(StorageAndCDNManagementEndpointModule.class)
.add(CloudFilesRestClientModule.class)
.add(CloudFilesBlobStoreContextModule.class)
.add(CloudFilesTemporaryUrlExtensionModule.class).build());
} }
@Override @Override
@ -93,4 +101,13 @@ public class CloudFilesApiMetadata extends SwiftApiMetadata {
} }
} }
public static class CloudFilesTemporaryUrlExtensionModule extends TemporaryUrlExtensionModule<CloudFilesAsyncClient> {
@Override
protected void bindRequestSigner() {
bind(BlobRequestSigner.class).to(new TypeLiteral<SwiftBlobSigner<CloudFilesAsyncClient>>() {
});
}
}
} }

View File

@ -23,16 +23,12 @@ import java.util.concurrent.TimeUnit;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.cloudfiles.CloudFilesClient; import org.jclouds.cloudfiles.CloudFilesClient;
import org.jclouds.openstack.swift.TemporaryUrlKey;
import org.jclouds.cloudfiles.blobstore.CloudFilesAsyncBlobStore; import org.jclouds.cloudfiles.blobstore.CloudFilesAsyncBlobStore;
import org.jclouds.cloudfiles.blobstore.CloudFilesBlobStore; import org.jclouds.cloudfiles.blobstore.CloudFilesBlobStore;
import org.jclouds.cloudfiles.blobstore.functions.CloudFilesObjectToBlobMetadata; import org.jclouds.cloudfiles.blobstore.functions.CloudFilesObjectToBlobMetadata;
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata; import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.date.TimeStamp;
import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore; import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore;
import org.jclouds.openstack.swift.blobstore.SwiftBlobRequestSigner;
import org.jclouds.openstack.swift.blobstore.SwiftBlobStore; import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule; import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata; import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
@ -70,6 +66,5 @@ public class CloudFilesBlobStoreContextModule extends SwiftBlobStoreContextModul
bind(SwiftBlobStore.class).to(CloudFilesBlobStore.class); bind(SwiftBlobStore.class).to(CloudFilesBlobStore.class);
bind(SwiftAsyncBlobStore.class).to(CloudFilesAsyncBlobStore.class); bind(SwiftAsyncBlobStore.class).to(CloudFilesAsyncBlobStore.class);
bind(ObjectToBlobMetadata.class).to(CloudFilesObjectToBlobMetadata.class); bind(ObjectToBlobMetadata.class).to(CloudFilesObjectToBlobMetadata.class);
bind(BlobRequestSigner.class).to(SwiftBlobRequestSigner.class);
} }
} }

View File

@ -53,6 +53,7 @@ public class CloudFilesRestClientModule extends SwiftRestClientModule<CloudFiles
.<Class<?>, Class<?>> of()); .<Class<?>, Class<?>> of());
} }
@Override
protected void bindResolvedClientsToCommonSwift() { protected void bindResolvedClientsToCommonSwift() {
bind(CommonSwiftClient.class).to(CloudFilesClient.class).in(Scopes.SINGLETON); bind(CommonSwiftClient.class).to(CloudFilesClient.class).in(Scopes.SINGLETON);
bind(CommonSwiftAsyncClient.class).to(CloudFilesAsyncClient.class).in(Scopes.SINGLETON); bind(CommonSwiftAsyncClient.class).to(CloudFilesAsyncClient.class).in(Scopes.SINGLETON);

View File

@ -0,0 +1,145 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.cloudfiles.blobstore;
import static org.jclouds.openstack.swift.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import java.util.Map;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.blobstore.internal.BaseBlobSignerExpectTest;
import org.jclouds.cloudfiles.CloudFilesApiMetadata;
import org.jclouds.cloudfiles.CloudFilesApiMetadata.CloudFilesTemporaryUrlExtensionModule;
import org.jclouds.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule;
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule;
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule.StorageAndCDNManagementEndpointModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.HttpHeaders;
import com.google.inject.Module;
/**
* Tests behavior of {@code SwiftBlobSigner}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during
// surefire
@Test(groups = "unit", testName = "CloudFilesBlobSignerExpectTest")
public class CloudFilesBlobSignerExpectTest extends BaseBlobSignerExpectTest {
public CloudFilesBlobSignerExpectTest() {
identity = "user@jclouds.org";
credential = "Password1234";
}
@Override
protected HttpRequest getBlob() {
return HttpRequest.builder().method("GET")
.endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container/name")
.addHeader("X-Auth-Token", authToken).build();
}
@Override
protected HttpRequest getBlobWithTime() {
return HttpRequest.builder().method("GET")
.endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container/name?temp_url_sig=9d62a4a15076699b3f7c60c2d021609990f24115&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest getBlobWithOptions() {
return HttpRequest.builder().method("GET")
.endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container/name")
.addHeader("X-Auth-Token", authToken)
.addHeader("Range", "bytes=0-1").build();
}
@Override
protected HttpRequest putBlob() {
return HttpRequest.builder().method("PUT")
.endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container/name")
.addHeader("X-Auth-Token", authToken).build();
}
@Override
protected HttpRequest putBlobWithTime() {
return HttpRequest.builder().method("PUT")
.endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container/name?temp_url_sig=f83fa711f353f6f0bab3a66c56e35a972b9b3922&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest removeBlob() {
return HttpRequest.builder().method("DELETE")
.endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/container/name")
.addHeader("X-Auth-Token", authToken).build();
}
protected String authToken = "118fb907-0786-4799-88f0-9a5b7963d1ab";
@Override
protected Map<HttpRequest, HttpResponse> init() {
HttpRequest authRequest = HttpRequest.builder().method("POST")
.endpoint("https://auth.api.rackspacecloud.com/v1.1/auth")
.addHeader(HttpHeaders.ACCEPT, "application/json")
.payload(
payloadFromStringWithContentType(
"{\"credentials\":{\"username\":\"user@jclouds.org\",\"key\":\"Password1234\"}}",
"application/json")).build();
HttpResponse authResponse = HttpResponse.builder().statusCode(200).message("HTTP/1.1 200")
.payload(payloadFromResourceWithContentType("/auth1_1.json", "application/json")).build();
HttpRequest temporaryKeyRequest = HttpRequest.builder().method("HEAD")
.endpoint("https://storage101.lon3.clouddrive.com/v1/MossoCloudFS_83a9d536-2e25-4166-bd3b-a503a934f953/")
.addHeader("X-Auth-Token", authToken).build();
HttpResponse temporaryKeyResponse = HttpResponse.builder().statusCode(200)
.addHeader(ACCOUNT_TEMPORARY_URL_KEY, "TEMPORARY_KEY").build();
return ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(authRequest, authResponse)
.put(temporaryKeyRequest, temporaryKeyResponse).build();
}
public static class StaticTimeAndTemporaryUrlKeyModule extends CloudFilesTemporaryUrlExtensionModule {
@Override
protected Long unixEpochTimestampProvider() {
return 123456789L;
}
}
@Override
protected ApiMetadata createApiMetadata() {
return new CloudFilesApiMetadata()
.toBuilder()
.defaultEndpoint("https://auth.api.rackspacecloud.com")
.defaultModules(
ImmutableSet.<Class<? extends Module>> builder()
.add(StorageAndCDNManagementEndpointModule.class)
.add(CloudFilesRestClientModule.class)
.add(CloudFilesBlobStoreContextModule.class)
.add(StaticTimeAndTemporaryUrlKeyModule.class).build()).build();
}
}

View File

@ -88,6 +88,7 @@ public class KeystoneRestClientModule<S extends KeystoneApi, A extends KeystoneA
.put(TenantApi.class, TenantAsyncApi.class) .put(TenantApi.class, TenantAsyncApi.class)
.build(); .build();
@SuppressWarnings("unchecked")
public KeystoneRestClientModule() { public KeystoneRestClientModule() {
super(TypeToken.class.cast(TypeToken.of(KeystoneApi.class)), TypeToken.class.cast(TypeToken.of(KeystoneAsyncApi.class)), DELEGATE_MAP); super(TypeToken.class.cast(TypeToken.of(KeystoneApi.class)), TypeToken.class.cast(TypeToken.of(KeystoneAsyncApi.class)), DELEGATE_MAP);
} }

View File

@ -1,128 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.s3.blobstore;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Date;
import javax.inject.Provider;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobBuilder;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.config.S3RestClientModule;
import org.jclouds.s3.internal.BaseS3AsyncClientTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code S3BlobRequestSigner}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "S3BlobRequestSignerTest")
public class S3BlobRequestSignerTest extends BaseS3AsyncClientTest<S3AsyncClient> {
@Override
protected TypeLiteral<RestAnnotationProcessor<S3AsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<S3AsyncClient>>() {
};
}
private BlobRequestSigner signer;
private Provider<BlobBuilder> blobFactory;
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET https://container.s3.amazonaws.com/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: AWS identity:0uvBv1wEskuhFHYJF/L6kEV9A7o=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nHost: container.s3.amazonaws.com\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignRemoveBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signRemoveBlob("container", "name");
assertRequestLineEquals(request, "DELETE https://container.s3.amazonaws.com/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: AWS identity:4FnyjdX/ULdDMRbVlLNjZfEo9RQ=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nHost: container.s3.amazonaws.com\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
Blob blob = blobFactory.get().name("name").forSigning().contentLength(2l).contentMD5(new byte[] { 0, 2, 4, 8 }).contentType(
"text/plain").expires(new Date(1000)).build();
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request, "PUT https://container.s3.amazonaws.com/name HTTP/1.1");
assertNonPayloadHeadersEqual(
request,
"Authorization: AWS identity:j9Dy/lmmvlCKjA4lkqZenLxMkR4=\nDate: Thu, 05 Jun 2008 16:38:19 GMT\nHost: container.s3.amazonaws.com\n");
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[] { 0, 2, 4, 8 }, new Date(1000));
assertEquals(request.getFilters().size(), 0);
}
@BeforeClass
protected void setupFactory() throws IOException {
super.setupFactory();
this.blobFactory = injector.getProvider(BlobBuilder.class);
this.signer = injector.getInstance(BlobRequestSigner.class);
}
@Override
protected Module createModule() {
return new TestS3RestClientModule();
}
@ConfiguresRestClient
private static final class TestS3RestClientModule extends S3RestClientModule<S3Client, S3AsyncClient> {
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "Thu, 05 Jun 2008 16:38:19 GMT";
}
}
}

View File

@ -0,0 +1,129 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.s3.blobstore;
import org.jclouds.blobstore.internal.BaseBlobSignerExpectTest;
import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.s3.S3AsyncClient;
import org.jclouds.s3.S3Client;
import org.jclouds.s3.config.S3RestClientModule;
import org.testng.SkipException;
import org.testng.annotations.Test;
import com.google.common.base.Supplier;
import com.google.inject.Module;
/**
* Tests behavior of {@code S3BlobRequestSigner}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "S3BlobSignerExpectTest")
public class S3BlobSignerExpectTest extends BaseBlobSignerExpectTest {
public S3BlobSignerExpectTest() {
provider = "s3";
}
@Override
protected HttpRequest getBlob() {
return HttpRequest.builder().method("GET")
.endpoint("https://container.s3.amazonaws.com/name")
.addHeader("Host", "container.s3.amazonaws.com")
.addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT")
.addHeader("Authorization", "AWS identity:0uvBv1wEskuhFHYJF/L6kEV9A7o=").build();
}
@Override
@Test
public void testSignGetBlobWithTime() {
throw new SkipException("not yet implemented");
}
//TODO
@Override
protected HttpRequest getBlobWithTime() {
return HttpRequest.builder().method("GET")
.endpoint("https://container.s3.amazonaws.com/name")
.addHeader("Host", "container.s3.amazonaws.com")
.addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT")
.addHeader("Authorization", "AWS identity:0uvBv1wEskuhFHYJF/L6kEV9A7o=").build();
}
@Override
protected HttpRequest getBlobWithOptions() {
return HttpRequest.builder().method("GET")
.endpoint("https://container.s3.amazonaws.com/name")
.addHeader("Range", "bytes=0-1")
.addHeader("Host", "container.s3.amazonaws.com")
.addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT")
.addHeader("Authorization", "AWS identity:0uvBv1wEskuhFHYJF/L6kEV9A7o=").build();
}
@Override
protected HttpRequest putBlob() {
return HttpRequest.builder().method("PUT")
.endpoint("https://container.s3.amazonaws.com/name")
.addHeader("Host", "container.s3.amazonaws.com")
.addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT")
.addHeader("Authorization", "AWS identity:j9Dy/lmmvlCKjA4lkqZenLxMkR4=").build();
}
@Override
@Test
public void testSignPutBlobWithTime() throws Exception {
throw new SkipException("not yet implemented");
}
//TODO
@Override
protected HttpRequest putBlobWithTime() {
return HttpRequest.builder().method("PUT")
.endpoint("https://container.s3.amazonaws.com/name")
.addHeader("Host", "container.s3.amazonaws.com")
.addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT")
.addHeader("Authorization", "AWS identity:0uvBv1wEskuhFHYJF/L6kEV9A7o=").build();
}
@Override
protected HttpRequest removeBlob() {
return HttpRequest.builder().method("DELETE")
.endpoint("https://container.s3.amazonaws.com/name")
.addHeader("Host", "container.s3.amazonaws.com")
.addHeader("Date", "Thu, 05 Jun 2008 16:38:19 GMT")
.addHeader("Authorization", "AWS identity:4FnyjdX/ULdDMRbVlLNjZfEo9RQ=").build();
}
@Override
protected Module createModule() {
return new TestS3RestClientModule();
}
@ConfiguresRestClient
private static final class TestS3RestClientModule extends S3RestClientModule<S3Client, S3AsyncClient> {
@Override
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return "Thu, 05 Jun 2008 16:38:19 GMT";
}
}
}

View File

@ -27,6 +27,7 @@ import java.util.Properties;
import org.jclouds.apis.ApiMetadata; import org.jclouds.apis.ApiMetadata;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule; import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.openstack.swift.blobstore.config.TemporaryUrlExtensionModule.SwiftTemporaryUrlExtensionModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule; import org.jclouds.openstack.swift.config.SwiftRestClientModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule.StorageEndpointModule; import org.jclouds.openstack.swift.config.SwiftRestClientModule.StorageEndpointModule;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
@ -81,7 +82,11 @@ public class SwiftApiMetadata extends BaseRestApiMetadata {
.defaultProperties(SwiftApiMetadata.defaultProperties()) .defaultProperties(SwiftApiMetadata.defaultProperties())
.view(TypeToken.of(BlobStoreContext.class)) .view(TypeToken.of(BlobStoreContext.class))
.context(CONTEXT_TOKEN) .context(CONTEXT_TOKEN)
.defaultModules(ImmutableSet.<Class<? extends Module>>of(StorageEndpointModule.class, SwiftRestClientModule.class, SwiftBlobStoreContextModule.class)); .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(StorageEndpointModule.class)
.add(SwiftRestClientModule.class)
.add(SwiftBlobStoreContextModule.class)
.add(SwiftTemporaryUrlExtensionModule.class).build());
} }
@Override @Override

View File

@ -29,6 +29,7 @@ import org.jclouds.openstack.keystone.v2_0.config.CredentialTypes;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule; import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
import org.jclouds.openstack.services.ServiceType; import org.jclouds.openstack.services.ServiceType;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule; import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.openstack.swift.blobstore.config.TemporaryUrlExtensionModule.SwiftKeystoneTemporaryUrlExtensionModule;
import org.jclouds.openstack.swift.config.SwiftKeystoneRestClientModule; import org.jclouds.openstack.swift.config.SwiftKeystoneRestClientModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule.KeystoneStorageEndpointModule; import org.jclouds.openstack.swift.config.SwiftRestClientModule.KeystoneStorageEndpointModule;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
@ -91,8 +92,12 @@ public class SwiftKeystoneApiMetadata extends SwiftApiMetadata {
.defaultEndpoint("http://localhost:5000/v2.0/") .defaultEndpoint("http://localhost:5000/v2.0/")
.context(CONTEXT_TOKEN) .context(CONTEXT_TOKEN)
.defaultProperties(SwiftKeystoneApiMetadata.defaultProperties()) .defaultProperties(SwiftKeystoneApiMetadata.defaultProperties())
.defaultModules(ImmutableSet.<Class<? extends Module>>of(KeystoneStorageEndpointModule.class, KeystoneAuthenticationModule.RegionModule.class, .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
SwiftKeystoneRestClientModule.class, SwiftBlobStoreContextModule.class)); .add(KeystoneStorageEndpointModule.class)
.add(KeystoneAuthenticationModule.RegionModule.class)
.add(SwiftKeystoneRestClientModule.class)
.add(SwiftBlobStoreContextModule.class)
.add(SwiftKeystoneTemporaryUrlExtensionModule.class).build());
} }
@Override @Override

View File

@ -20,8 +20,6 @@ package org.jclouds.openstack.swift.blobstore;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.collect.Iterables.filter;
import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest; import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -30,9 +28,6 @@ import java.security.InvalidKeyException;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.inject.Provider;
import org.jclouds.blobstore.BlobRequestSigner; import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions; import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
@ -40,21 +35,26 @@ import org.jclouds.crypto.Crypto;
import org.jclouds.crypto.CryptoStreams; import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.swift.CommonSwiftAsyncClient; import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.TemporaryUrlKey; import org.jclouds.openstack.swift.TemporaryUrlKey;
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject; import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
import org.jclouds.openstack.swift.domain.SwiftObject; import org.jclouds.openstack.swift.domain.SwiftObject;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import com.google.common.base.Supplier;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Provider;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class SwiftBlobRequestSigner implements BlobRequestSigner { public class SwiftBlobSigner<T extends CommonSwiftAsyncClient> implements BlobRequestSigner {
private final RestAnnotationProcessor<CommonSwiftAsyncClient> processor; private final RestAnnotationProcessor<T> processor;
private final Crypto crypto; private final Crypto crypto;
private final Provider<Long> unixEpochTimestampProvider; private final Provider<Long> unixEpochTimestampProvider;
@ -67,10 +67,18 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
private final Method deleteMethod; private final Method deleteMethod;
private final Method createMethod; private final Method createMethod;
/**
* create a signer for this subtype of swift
*
* @param processor
* bound to the current subclass of {@link CommonSwiftAsyncClient}
*/
@Inject @Inject
public SwiftBlobRequestSigner(RestAnnotationProcessor<CommonSwiftAsyncClient> processor, BlobToObject blobToObject, protected SwiftBlobSigner(BlobToObject blobToObject, BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto,
BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto, @TimeStamp Provider<Long> unixEpochTimestampProvider, @TimeStamp Provider<Long> unixEpochTimestampProvider,
@TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier) throws SecurityException, NoSuchMethodException { @TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier,
RestAnnotationProcessor<T> processor)
throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor"); this.processor = checkNotNull(processor, "processor");
this.crypto = checkNotNull(crypto, "crypto"); this.crypto = checkNotNull(crypto, "crypto");
@ -80,10 +88,9 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
this.blobToObject = checkNotNull(blobToObject, "blobToObject"); this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions"); this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions");
this.getMethod = CommonSwiftAsyncClient.class.getMethod("getObject", String.class, String.class, this.getMethod = processor.getDeclaring().getMethod("getObject", String.class, String.class, GetOptions[].class);
GetOptions[].class); this.deleteMethod = processor.getDeclaring().getMethod("removeObject", String.class, String.class);
this.deleteMethod = CommonSwiftAsyncClient.class.getMethod("removeObject", String.class, String.class); this.createMethod = processor.getDeclaring().getMethod("putObject", String.class, SwiftObject.class);
this.createMethod = CommonSwiftAsyncClient.class.getMethod("putObject", String.class, SwiftObject.class);
} }
@Override @Override
@ -119,8 +126,7 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
} }
private HttpRequest signForTemporaryAccess(HttpRequest request, long timeInSeconds) { private HttpRequest signForTemporaryAccess(HttpRequest request, long timeInSeconds) {
HttpRequest.Builder builder = request.toBuilder(); HttpRequest.Builder<?> builder = request.toBuilder().filters(ImmutableSet.<HttpRequestFilter>of());
builder.filters(filter(request.getFilters(), instanceOf(AuthenticateRequest.class)));
String key = temporaryUrlKeySupplier.get(); String key = temporaryUrlKeySupplier.get();
if (key == null) { if (key == null) {
@ -128,8 +134,8 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
} }
long expiresInSeconds = unixEpochTimestampProvider.get() + timeInSeconds; long expiresInSeconds = unixEpochTimestampProvider.get() + timeInSeconds;
builder.addQueryParam("temp_url_sig", createSignature(key, createStringToSign( builder.addQueryParam("temp_url_sig",
request.getMethod().toUpperCase(), request, expiresInSeconds))); createSignature(key, createStringToSign(request.getMethod().toUpperCase(), request, expiresInSeconds)));
builder.addQueryParam("temp_url_expires", "" + expiresInSeconds); builder.addQueryParam("temp_url_expires", "" + expiresInSeconds);
return builder.build(); return builder.build();
@ -137,14 +143,12 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
private String createStringToSign(String method, HttpRequest request, long expiresInSeconds) { private String createStringToSign(String method, HttpRequest request, long expiresInSeconds) {
checkArgument(method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("PUT")); checkArgument(method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("PUT"));
return String.format("%s\n%d\n%s", method.toUpperCase(), expiresInSeconds, return String.format("%s\n%d\n%s", method.toUpperCase(), expiresInSeconds, request.getEndpoint().getPath());
request.getEndpoint().getPath());
} }
private String createSignature(String key, String stringToSign) { private String createSignature(String key, String stringToSign) {
try { try {
return CryptoStreams.hex(crypto.hmacSHA1(key.getBytes()).doFinal(stringToSign.getBytes())); return CryptoStreams.hex(crypto.hmacSHA1(key.getBytes()).doFinal(stringToSign.getBytes()));
} catch (InvalidKeyException e) { } catch (InvalidKeyException e) {
throw Throwables.propagate(e); throw Throwables.propagate(e);
} }

View File

@ -18,57 +18,30 @@
*/ */
package org.jclouds.openstack.swift.blobstore.config; package org.jclouds.openstack.swift.blobstore.config;
import com.google.common.base.Supplier;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.date.TimeStamp;
import org.jclouds.openstack.swift.TemporaryUrlKey;
import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore; import org.jclouds.openstack.swift.blobstore.SwiftAsyncBlobStore;
import org.jclouds.openstack.swift.blobstore.SwiftBlobRequestSigner;
import org.jclouds.openstack.swift.blobstore.SwiftBlobStore; import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyAsyncApi;
import org.jclouds.openstack.swift.suppliers.ReturnOrFetchTemporaryUrlKey;
import java.util.UUID;
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
/** /**
* Configures the {@link CloudFilesBlobStoreContext}; requires {@link SwiftAsyncBlobStore} * Configures the {@link CloudFilesBlobStoreContext}; requires
* bound. * {@link SwiftAsyncBlobStore} bound.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class SwiftBlobStoreContextModule extends AbstractModule { public class SwiftBlobStoreContextModule extends AbstractModule {
@Provides
@TimeStamp
protected Long unixEpochTimestampProvider() {
return System.currentTimeMillis() / 1000; /* convert to seconds */
}
@Override @Override
protected void configure() { protected void configure() {
install(new BlobStoreMapModule()); install(new BlobStoreMapModule());
bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT); bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
bind(AsyncBlobStore.class).to(SwiftAsyncBlobStore.class).in(Scopes.SINGLETON); bind(AsyncBlobStore.class).to(SwiftAsyncBlobStore.class).in(Scopes.SINGLETON);
bind(BlobStore.class).to(SwiftBlobStore.class).in(Scopes.SINGLETON); bind(BlobStore.class).to(SwiftBlobStore.class).in(Scopes.SINGLETON);
bind(BlobRequestSigner.class).to(SwiftBlobRequestSigner.class);
configureTemporaryUrlExtension();
}
protected void configureTemporaryUrlExtension() {
bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, TemporaryUrlKeyAsyncApi.class);
bind(new TypeLiteral<Supplier<String>>() {
}).annotatedWith(TemporaryUrlKey.class).to(ReturnOrFetchTemporaryUrlKey.class);
} }
} }

View File

@ -0,0 +1,97 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.swift.blobstore.config;
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.date.TimeStamp;
import org.jclouds.openstack.swift.CommonSwiftAsyncClient;
import org.jclouds.openstack.swift.SwiftAsyncClient;
import org.jclouds.openstack.swift.SwiftKeystoneAsyncClient;
import org.jclouds.openstack.swift.TemporaryUrlKey;
import org.jclouds.openstack.swift.blobstore.SwiftBlobSigner;
import org.jclouds.openstack.swift.extensions.KeystoneTemporaryUrlKeyAsyncApi;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyAsyncApi;
import org.jclouds.openstack.swift.suppliers.ReturnOrFetchTemporaryUrlKey;
import com.google.common.base.Supplier;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
* Isolates dependencies needed for {@link SwiftBlobSigner}
*
* @author Adrian Cole
*
*/
public abstract class TemporaryUrlExtensionModule<A extends CommonSwiftAsyncClient> extends AbstractModule {
public static class SwiftTemporaryUrlExtensionModule extends TemporaryUrlExtensionModule<SwiftAsyncClient> {
@Override
protected void bindRequestSigner() {
bind(BlobRequestSigner.class).to(new TypeLiteral<SwiftBlobSigner<SwiftAsyncClient>>() {
});
}
}
/**
* Ensures keystone auth is used instead of swift auth
*
*/
public static class SwiftKeystoneTemporaryUrlExtensionModule extends
TemporaryUrlExtensionModule<SwiftKeystoneAsyncClient> {
protected void bindTemporaryUrlKeyApi() {
bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, KeystoneTemporaryUrlKeyAsyncApi.class);
}
@Override
protected void bindRequestSigner() {
bind(BlobRequestSigner.class).to(new TypeLiteral<SwiftBlobSigner<SwiftKeystoneAsyncClient>>() {
});
}
}
@Provides
@TimeStamp
protected Long unixEpochTimestampProvider() {
return System.currentTimeMillis() / 1000; /* convert to seconds */
}
@Override
protected void configure() {
bindRequestSigner();
bindTemporaryUrlKeyApi();
bind(new TypeLiteral<Supplier<String>>() {
}).annotatedWith(TemporaryUrlKey.class).to(ReturnOrFetchTemporaryUrlKey.class);
}
protected abstract void bindRequestSigner();
protected void bindTemporaryUrlKeyApi() {
bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, TemporaryUrlKeyAsyncApi.class);
}
}

View File

@ -25,5 +25,5 @@ public class SwiftKeystoneRestClientModule extends SwiftRestClientModule<SwiftKe
protected void bindResolvedClientsToCommonSwift() { protected void bindResolvedClientsToCommonSwift() {
bind(CommonSwiftClient.class).to(SwiftKeystoneClient.class).in(Scopes.SINGLETON); bind(CommonSwiftClient.class).to(SwiftKeystoneClient.class).in(Scopes.SINGLETON);
bind(CommonSwiftAsyncClient.class).to(SwiftKeystoneAsyncClient.class).in(Scopes.SINGLETON); bind(CommonSwiftAsyncClient.class).to(SwiftKeystoneAsyncClient.class).in(Scopes.SINGLETON);
} }
} }

View File

@ -58,16 +58,17 @@ import com.google.inject.Scopes;
* @author Adrian Cole * @author Adrian Cole
*/ */
@ConfiguresRestClient @ConfiguresRestClient
public class SwiftRestClientModule<S extends CommonSwiftClient, A extends CommonSwiftAsyncClient> extends RestClientModule<S, A> { public class SwiftRestClientModule<S extends CommonSwiftClient, A extends CommonSwiftAsyncClient> extends
RestClientModule<S, A> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public SwiftRestClientModule() { public SwiftRestClientModule() {
this(TypeToken.class.cast(TypeToken.of(SwiftClient.class)), TypeToken.class.cast(TypeToken this(TypeToken.class.cast(TypeToken.of(SwiftClient.class)), TypeToken.class.cast(TypeToken
.of(SwiftAsyncClient.class)), ImmutableMap.<Class<?>, Class<?>> of()); .of(SwiftAsyncClient.class)), ImmutableMap.<Class<?>, Class<?>> of());
} }
protected SwiftRestClientModule(TypeToken<S> syncClientType, TypeToken<A> asyncClientType, protected SwiftRestClientModule(TypeToken<S> syncClientType, TypeToken<A> asyncClientType,
Map<Class<?>, Class<?>> sync2Async) { Map<Class<?>, Class<?>> sync2Async) {
super(syncClientType, asyncClientType, sync2Async); super(syncClientType, asyncClientType, sync2Async);
} }

View File

@ -0,0 +1,38 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.swift.extensions;
import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest;
import org.jclouds.openstack.swift.Storage;
import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.SkipEncoding;
/**
* Only purpose is to override the auth filter with one that works in keystone
*
* @author Adrian Cole
* @see TemporaryUrlKeyApi
*/
@SkipEncoding('/')
@RequestFilters(AuthenticateRequest.class)
@Endpoint(Storage.class)
public interface KeystoneTemporaryUrlKeyAsyncApi extends TemporaryUrlKeyAsyncApi {
}

View File

@ -18,14 +18,12 @@
*/ */
package org.jclouds.openstack.swift.functions; package org.jclouds.openstack.swift.functions;
import com.google.common.base.Function;
import com.google.common.collect.Multimap;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.swift.reference.SwiftHeaders;
import static com.google.common.collect.Iterables.getOnlyElement;
import static org.jclouds.openstack.swift.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY; import static org.jclouds.openstack.swift.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import org.jclouds.http.HttpResponse;
import com.google.common.base.Function;
/** /**
* @author Andrei Savu * @author Andrei Savu
*/ */
@ -33,11 +31,6 @@ public class ParseTemporaryUrlKeyFromHeaders implements Function<HttpResponse, S
@Override @Override
public String apply(HttpResponse httpResponse) { public String apply(HttpResponse httpResponse) {
Multimap<String, String> headers = httpResponse.getHeaders(); return httpResponse.getFirstHeaderOrNull(ACCOUNT_TEMPORARY_URL_KEY);
if (headers.containsKey(ACCOUNT_TEMPORARY_URL_KEY)) {
return getOnlyElement(headers.get(ACCOUNT_TEMPORARY_URL_KEY));
} else {
return null;
}
} }
} }

View File

@ -21,33 +21,32 @@ package org.jclouds.openstack.swift;
import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS; import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
import java.net.URI; import java.net.URI;
import java.util.Properties; import java.util.Properties;
import javax.inject.Singleton; import javax.inject.Singleton;
import com.google.common.base.Suppliers;
import com.google.inject.*;
import com.google.inject.util.Modules;
import org.jclouds.apis.ApiMetadata; import org.jclouds.apis.ApiMetadata;
import org.jclouds.date.TimeStamp; import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService; import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
import org.jclouds.openstack.internal.TestOpenStackAuthenticationModule; import org.jclouds.openstack.internal.TestOpenStackAuthenticationModule;
import org.jclouds.openstack.reference.AuthHeaders; import org.jclouds.openstack.reference.AuthHeaders;
import org.jclouds.openstack.swift.blobstore.SwiftBlobSigner;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule; import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.openstack.swift.blobstore.config.TemporaryUrlExtensionModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule; import org.jclouds.openstack.swift.config.SwiftRestClientModule;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyAsyncApi;
import org.jclouds.openstack.swift.suppliers.ReturnOrFetchTemporaryUrlKey;
import org.jclouds.rest.internal.BaseAsyncClientTest; import org.jclouds.rest.internal.BaseAsyncClientTest;
import org.jclouds.rest.internal.RestAnnotationProcessor; import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/** /**
* Tests behavior of {@code BindSwiftObjectMetadataToRequest} * Tests behavior of {@code BindSwiftObjectMetadataToRequest}
@ -83,25 +82,34 @@ public abstract class CommonSwiftClientTest extends BaseAsyncClientTest<SwiftAsy
} }
} }
public static class StaticTimeAndTemporaryUrlKeyModule extends SwiftBlobStoreContextModule { public static class StaticTimeAndTemporaryUrlKeyModule extends TemporaryUrlExtensionModule<SwiftAsyncClient> {
@Override @Override
protected Long unixEpochTimestampProvider() { protected Long unixEpochTimestampProvider() {
return UNIX_EPOCH_TIMESTAMP; return UNIX_EPOCH_TIMESTAMP;
} }
@Override @Override
protected void configureTemporaryUrlExtension() { protected void configure() {
bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, TemporaryUrlKeyAsyncApi.class); bindTemporaryUrlKeyApi();
bind(new TypeLiteral<Supplier<String>>() { bind(new TypeLiteral<Supplier<String>>() {
}).annotatedWith(TemporaryUrlKey.class).toInstance(Suppliers.ofInstance(TEMPORARY_URL_KEY)); }).annotatedWith(TemporaryUrlKey.class).toInstance(Suppliers.ofInstance(TEMPORARY_URL_KEY));
} }
@Override
protected void bindRequestSigner() {
bind(BlobRequestSigner.class).to(new TypeLiteral<SwiftBlobSigner<SwiftAsyncClient>>() {
});
}
} }
@Override @Override
protected ApiMetadata createApiMetadata() { protected ApiMetadata createApiMetadata() {
return new SwiftApiMetadata().toBuilder().defaultModules( return new SwiftApiMetadata().toBuilder()
ImmutableSet.<Class<? extends Module>>of(StorageEndpointModule.class, SwiftRestClientModule.class, .defaultModules(ImmutableSet.<Class<? extends Module>>builder()
StaticTimeAndTemporaryUrlKeyModule.class)).build(); .add(StorageEndpointModule.class)
.add(SwiftRestClientModule.class)
.add(SwiftBlobStoreContextModule.class)
.add(StaticTimeAndTemporaryUrlKeyModule.class).build()).build();
} }
@Override @Override

View File

@ -1,124 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.swift.blobstore;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import java.io.IOException;
import java.util.Date;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.http.HttpRequest;
import org.jclouds.openstack.swift.CommonSwiftClientTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code CommonSwiftBlobRequestSigner}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "SwiftBlobRequestSignerTest")
public class SwiftBlobRequestSignerTest extends CommonSwiftClientTest {
private BlobRequestSigner signer;
private Factory blobFactory;
public void testSignGetBlob() throws Exception {
HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET http://storage/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignGetBlobWithTime() {
HttpRequest request = signer.signGetBlob("container", "name", 120);
assertRequestLineEquals(request, "GET http://storage/container/name?" +
"temp_url_sig=4759d99d13c826bba0af2c9f0c526ca53c95abaf&temp_url_expires=123456909 HTTP/1.1");
assertFalse(request.getHeaders().containsKey("X-Auth-Token"));
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlob() throws Exception {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload("");
blob.getPayload().getContentMetadata().setContentLength(2l);
blob.getPayload().getContentMetadata().setContentMD5(new byte[] { 0, 2, 4, 8 });
blob.getPayload().getContentMetadata().setContentType("text/plain");
blob.getPayload().getContentMetadata().setExpires(new Date(1000));
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request, "PUT http://storage/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[] { 0, 2, 4, 8 }, new Date(1000));
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlobWithTime() throws Exception {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload("");
blob.getPayload().getContentMetadata().setContentLength(2l);
blob.getPayload().getContentMetadata().setContentMD5(new byte[]{0, 2, 4, 8});
blob.getPayload().getContentMetadata().setContentType("text/plain");
blob.getPayload().getContentMetadata().setExpires(new Date(1000));
HttpRequest request = signer.signPutBlob("container", blob, 120 /* seconds */);
assertRequestLineEquals(request, "PUT http://storage/container/name?" +
"temp_url_sig=490690286130adac9e7144d85b320a00b1bf9e2b&temp_url_expires=123456909 HTTP/1.1");
assertFalse(request.getHeaders().containsKey("X-Auth-Token"));
assertContentHeadersEqual(request, "text/plain", null, null, null, (long) 2l, new byte[]{0, 2, 4, 8}, new Date(1000));
assertEquals(request.getFilters().size(), 0);
}
public void testSignRemoveBlob() throws Exception {
HttpRequest request = signer.signRemoveBlob("container", "name");
assertRequestLineEquals(request, "DELETE http://storage/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "X-Auth-Token: testtoken\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
@BeforeClass
protected void setupFactory() throws IOException {
super.setupFactory();
this.blobFactory = injector.getInstance(Blob.Factory.class);
this.signer = injector.getInstance(BlobRequestSigner.class);
}
}

View File

@ -0,0 +1,140 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.swift.blobstore;
import static org.jclouds.openstack.swift.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import java.util.Map;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.blobstore.internal.BaseBlobSignerExpectTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.swift.CommonSwiftClientTest.StorageEndpointModule;
import org.jclouds.openstack.swift.SwiftApiMetadata;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.openstack.swift.blobstore.config.TemporaryUrlExtensionModule.SwiftTemporaryUrlExtensionModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Tests behavior of {@code SwiftBlobRequestSigner}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "SwiftBlobSignerExpectTest")
public class SwiftBlobSignerExpectTest extends BaseBlobSignerExpectTest {
public SwiftBlobSignerExpectTest() {
identity = "test:tester";
credential = "testing";
}
@Override
protected HttpRequest getBlob() {
return HttpRequest.builder().method("GET")
.endpoint("http://storage/container/name")
.addHeader("X-Auth-Token", "testtoken").build();
}
@Override
protected HttpRequest getBlobWithTime() {
return HttpRequest.builder().method("GET")
.endpoint("http://storage/container/name?temp_url_sig=2abd47f6b1c159fe9a45c873aaade8eeeb36a2e1&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest getBlobWithOptions() {
return HttpRequest.builder().method("GET")
.endpoint("http://storage/container/name")
.addHeader("X-Auth-Token", "testtoken")
.addHeader("Range", "bytes=0-1").build();
}
@Override
protected HttpRequest putBlob() {
return HttpRequest.builder().method("PUT")
.endpoint("http://storage/container/name")
.addHeader("X-Auth-Token", "testtoken").build();
}
@Override
protected HttpRequest putBlobWithTime() {
return HttpRequest.builder().method("PUT")
.endpoint("http://storage/container/name?temp_url_sig=e894c60fa1284cc575cf22d7786bab07b8c33610&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest removeBlob() {
return HttpRequest.builder().method("DELETE")
.endpoint("http://storage/container/name")
.addHeader("X-Auth-Token", "testtoken").build();
}
@Override
protected Map<HttpRequest, HttpResponse> init() {
HttpRequest authRequest = HttpRequest.builder().method("GET")
.endpoint("http://auth/v1.0")
.addHeader("X-Auth-User", identity)
.addHeader("X-Auth-Key", credential)
.addHeader("Accept", "*/*")
.addHeader("Host", "myhost:8080").build();
HttpResponse authResponse = HttpResponse.builder().statusCode(200)
.message("HTTP/1.1 200 OK")
.addHeader("X-Storage-Url", "http://storage")
.addHeader("X-Auth-Token", "testtoken").build();
HttpRequest temporaryKeyRequest = HttpRequest.builder().method("HEAD")
.endpoint("http://storage/")
.addHeader("X-Auth-Token", "testtoken").build();
HttpResponse temporaryKeyResponse = HttpResponse.builder().statusCode(200)
.addHeader(ACCOUNT_TEMPORARY_URL_KEY, "TEMPORARY_KEY").build();
return ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(authRequest, authResponse)
.put(temporaryKeyRequest, temporaryKeyResponse).build();
}
public static class StaticTimeAndTemporaryUrlKeyModule extends SwiftTemporaryUrlExtensionModule {
@Override
protected Long unixEpochTimestampProvider() {
return 123456789L;
}
}
@Override
protected ApiMetadata createApiMetadata() {
return new SwiftApiMetadata()
.toBuilder()
.defaultEndpoint("http://auth")
.defaultModules(
ImmutableSet.<Class<? extends Module>> builder()
.add(StorageEndpointModule.class)
.add(SwiftRestClientModule.class)
.add(SwiftBlobStoreContextModule.class)
.add(StaticTimeAndTemporaryUrlKeyModule.class).build()).build();
}
}

View File

@ -0,0 +1,142 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.openstack.swift.blobstore;
import static org.jclouds.openstack.swift.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import java.util.Map;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.blobstore.internal.BaseBlobSignerExpectTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule;
import org.jclouds.openstack.swift.SwiftKeystoneApiMetadata;
import org.jclouds.openstack.swift.blobstore.config.SwiftBlobStoreContextModule;
import org.jclouds.openstack.swift.blobstore.config.TemporaryUrlExtensionModule.SwiftKeystoneTemporaryUrlExtensionModule;
import org.jclouds.openstack.swift.config.SwiftKeystoneRestClientModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule.KeystoneStorageEndpointModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Tests behavior of {@code SwiftBlobRequestSigner}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "SwiftKeystoneBlobSignerExpectTest")
public class SwiftKeystoneBlobSignerExpectTest extends BaseBlobSignerExpectTest {
@Override
protected HttpRequest getBlob() {
return HttpRequest.builder().method("GET")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
}
@Override
protected HttpRequest getBlobWithTime() {
return HttpRequest.builder().method("GET")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name?temp_url_sig=fd9b09acbc3ce71182240503c803dda4902098a9&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest getBlobWithOptions() {
return HttpRequest.builder().method("GET")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").addHeader("Range", "bytes=0-1").build();
}
@Override
protected HttpRequest putBlob() {
return HttpRequest.builder().method("PUT")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
}
@Override
protected HttpRequest putBlobWithTime() {
return HttpRequest.builder().method("PUT")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name?temp_url_sig=72e5f6ebafab2b3da0586198797e58fb7478211e&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest removeBlob() {
return HttpRequest.builder().method("DELETE")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
}
/**
* add the keystone commands
*/
@Override
protected Map<HttpRequest, HttpResponse> init() {
HttpRequest authenticate = HttpRequest
.builder()
.method("POST")
.endpoint("http://localhost:5000/v2.0/tokens")
.addHeader("Accept", "application/json")
.payload(
payloadFromStringWithContentType(
"{\"auth\":{\"passwordCredentials\":{\"username\":\"identity\",\"password\":\"credential\"}}}",
"application/json")).build();
HttpResponse authenticationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/keystoneAuthResponse.json", "application/json"))
.build();
HttpRequest temporaryKeyRequest = HttpRequest
.builder()
.method("HEAD")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
HttpResponse temporaryKeyResponse = HttpResponse.builder().statusCode(200)
.addHeader(ACCOUNT_TEMPORARY_URL_KEY, "TEMPORARY_KEY").build();
return ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(authenticate, authenticationResponse)
.put(temporaryKeyRequest, temporaryKeyResponse).build();
}
public static class StaticTimeAndTemporaryUrlKeyModule extends SwiftKeystoneTemporaryUrlExtensionModule {
public static final long UNIX_EPOCH_TIMESTAMP = 123456789L;
@Override
protected Long unixEpochTimestampProvider() {
return UNIX_EPOCH_TIMESTAMP;
}
}
@Override
protected ApiMetadata createApiMetadata() {
return new SwiftKeystoneApiMetadata().toBuilder()
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(KeystoneStorageEndpointModule.class)
.add(KeystoneAuthenticationModule.RegionModule.class)
.add(SwiftKeystoneRestClientModule.class)
.add(SwiftBlobStoreContextModule.class)
.add(StaticTimeAndTemporaryUrlKeyModule.class).build()).build();
}
}

View File

@ -19,16 +19,11 @@
package org.jclouds.openstack.swift.blobstore.integration; package org.jclouds.openstack.swift.blobstore.integration;
import java.util.Properties; import java.util.Properties;
import java.util.UUID;
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest; import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties; import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
/** /**
* *
* @author James Murty * @author James Murty

View File

@ -31,7 +31,6 @@ import java.util.concurrent.ExecutorService;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.ws.rs.HeaderParam;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.blobstore.LocalAsyncBlobStore; import org.jclouds.blobstore.LocalAsyncBlobStore;
@ -61,7 +60,6 @@ import com.google.common.base.Throwables;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import org.jclouds.openstack.swift.reference.SwiftHeaders;
/** /**
* Implementation of {@link SwiftAsyncClient} which keeps all data in a local Map object. * Implementation of {@link SwiftAsyncClient} which keeps all data in a local Map object.

View File

@ -0,0 +1,121 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.blobstore.internal;
import static org.jclouds.blobstore.options.GetOptions.Builder.range;
import static org.testng.Assert.assertEquals;
import java.util.Date;
import java.util.Map;
import java.util.Properties;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.options.GetOptions;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.rest.internal.BaseRestClientExpectTest;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Module;
/**
* @author Adrian Cole
*/
public abstract class BaseBlobSignerExpectTest extends BaseRestClientExpectTest<BlobStore> {
/**
* define the requests and responses needed to initialize the blobstore. For
* example, you may need to add in discovery requests needed (ex. KeyStone in
*/
protected Map<HttpRequest, HttpResponse> init() {
return ImmutableMap.<HttpRequest, HttpResponse> of();
}
protected String container = "container";
protected String name = "name";
protected String text = "fooooooooooooooooooooooo";
protected GetOptions options = range(0, 1);
@Test
public void testSignGetBlob() {
BlobStore getBlob = requestsSendResponses(init());
assertEquals(getBlob.getContext().getSigner().signGetBlob(container, name), getBlob());
}
protected abstract HttpRequest getBlob();
@Test
public void testSignGetBlobWithTime() {
BlobStore getBlobWithTime = requestsSendResponses(init());
HttpRequest compare = getBlobWithTime();
assertEquals(getBlobWithTime.getContext().getSigner().signGetBlob(container, name, 3l /* seconds */),
compare);
}
protected abstract HttpRequest getBlobWithTime();
@Test
public void testSignGetBlobWithOptions() {
BlobStore getBlobWithOptions = requestsSendResponses(init());
assertEquals(getBlobWithOptions.getContext().getSigner().signGetBlob(container, name, options),
getBlobWithOptions());
}
protected abstract HttpRequest getBlobWithOptions();
@Test
public void testSignRemoveBlob() {
BlobStore removeBlob = requestsSendResponses(init());
assertEquals(removeBlob.getContext().getSigner().signRemoveBlob(container, name), removeBlob());
}
@Test
public void testSignPutBlob() throws Exception {
BlobStore signPutBlob = requestsSendResponses(init());
Blob blob = signPutBlob.blobBuilder("name").forSigning().contentLength(2l).contentMD5(new byte[] { 0, 2, 4, 8 })
.contentType("text/plain").expires(new Date(1000)).build();
HttpRequest compare = putBlob();
compare.setPayload(blob.getPayload());
assertEquals(signPutBlob.getContext().getSigner().signPutBlob(container, blob), compare);
}
protected abstract HttpRequest putBlob();
@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);
}
protected abstract HttpRequest putBlobWithTime();
protected abstract HttpRequest removeBlob();
@Override
public BlobStore createClient(Function<HttpRequest, HttpResponse> fn, Module module, Properties props) {
return createInjector(fn, module, props).getInstance(BlobStore.class);
}
}

View File

@ -26,8 +26,6 @@ import org.jclouds.io.ContentMetadataBuilder;
import org.jclouds.io.MutableContentMetadata; import org.jclouds.io.MutableContentMetadata;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import com.google.common.collect.Multimap;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */

View File

@ -1334,4 +1334,10 @@ public class RestAnnotationProcessor<T> {
return postParams; return postParams;
} }
/**
* the class that is being processed
*/
public Class<T> getDeclaring(){
return declaring;
}
} }

View File

@ -18,20 +18,28 @@
*/ */
package org.jclouds.hpcloud.objectstorage; package org.jclouds.hpcloud.objectstorage;
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
import java.net.URI; import java.net.URI;
import java.util.Properties; import java.util.Properties;
import org.jclouds.apis.ApiMetadata; import org.jclouds.apis.ApiMetadata;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.hpcloud.objectstorage.blobstore.config.HPCloudObjectStorageBlobStoreContextModule; import org.jclouds.hpcloud.objectstorage.blobstore.config.HPCloudObjectStorageBlobStoreContextModule;
import org.jclouds.hpcloud.objectstorage.config.HPCloudObjectStorageRestClientModule; import org.jclouds.hpcloud.objectstorage.config.HPCloudObjectStorageRestClientModule;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule; import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
import org.jclouds.openstack.swift.SwiftKeystoneApiMetadata; import org.jclouds.openstack.swift.SwiftKeystoneApiMetadata;
import org.jclouds.openstack.swift.blobstore.SwiftBlobSigner;
import org.jclouds.openstack.swift.blobstore.config.TemporaryUrlExtensionModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule.KeystoneStorageEndpointModule; import org.jclouds.openstack.swift.config.SwiftRestClientModule.KeystoneStorageEndpointModule;
import org.jclouds.openstack.swift.extensions.KeystoneTemporaryUrlKeyAsyncApi;
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
import org.jclouds.rest.RestContext; import org.jclouds.rest.RestContext;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/** /**
* Implementation of {@link org.jclouds.providers.ProviderMetadata} for HP Cloud Services Object Storage * Implementation of {@link org.jclouds.providers.ProviderMetadata} for HP Cloud Services Object Storage
* *
@ -82,7 +90,8 @@ public class HPCloudObjectStorageApiMetadata extends SwiftKeystoneApiMetadata {
.add(KeystoneStorageEndpointModule.class) .add(KeystoneStorageEndpointModule.class)
.add(RegionModule.class) .add(RegionModule.class)
.add(HPCloudObjectStorageRestClientModule.class) .add(HPCloudObjectStorageRestClientModule.class)
.add(HPCloudObjectStorageBlobStoreContextModule.class).build()); .add(HPCloudObjectStorageBlobStoreContextModule.class)
.add(HPCloudObjectStorageTemporaryUrlExtensionModule.class).build());
} }
@Override @Override
@ -96,4 +105,24 @@ public class HPCloudObjectStorageApiMetadata extends SwiftKeystoneApiMetadata {
return this; return this;
} }
} }
/**
* Ensures keystone auth is used instead of swift auth
*
*/
public static class HPCloudObjectStorageTemporaryUrlExtensionModule extends
TemporaryUrlExtensionModule<HPCloudObjectStorageAsyncApi> {
@Override
protected void bindRequestSigner() {
bind(BlobRequestSigner.class).to(new TypeLiteral<SwiftBlobSigner<HPCloudObjectStorageAsyncApi>>() {
});
}
@Override
protected void bindTemporaryUrlKeyApi() {
bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, KeystoneTemporaryUrlKeyAsyncApi.class);
}
}
} }

View File

@ -1,75 +0,0 @@
package org.jclouds.hpcloud.objectstorage.blobstore;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.blobstore.util.BlobStoreUtils.cleanRequest;
import java.lang.reflect.Method;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncApi;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.options.GetOptions;
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
import org.jclouds.openstack.swift.domain.SwiftObject;
import org.jclouds.rest.internal.RestAnnotationProcessor;
/**
* @author Adrian Cole
*/
@Singleton
public class HPCloudObjectStorageBlobRequestSigner implements BlobRequestSigner {
private final RestAnnotationProcessor<HPCloudObjectStorageAsyncApi> processor;
private final BlobToObject blobToObject;
private final BlobToHttpGetOptions blob2HttpGetOptions;
private final Method getMethod;
private final Method deleteMethod;
private final Method createMethod;
@Inject
public HPCloudObjectStorageBlobRequestSigner(RestAnnotationProcessor<HPCloudObjectStorageAsyncApi> processor, BlobToObject blobToObject,
BlobToHttpGetOptions blob2HttpGetOptions) throws SecurityException, NoSuchMethodException {
this.processor = checkNotNull(processor, "processor");
this.blobToObject = checkNotNull(blobToObject, "blobToObject");
this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions");
this.getMethod = HPCloudObjectStorageAsyncApi.class.getMethod("getObject", String.class, String.class,
GetOptions[].class);
this.deleteMethod = HPCloudObjectStorageAsyncApi.class.getMethod("removeObject", String.class, String.class);
this.createMethod = HPCloudObjectStorageAsyncApi.class.getMethod("putObject", String.class, SwiftObject.class);
}
@Override
public HttpRequest signGetBlob(String container, String name) {
return cleanRequest(processor.createRequest(getMethod, container, name));
}
@Override
public HttpRequest signGetBlob(String container, String name, long timeInSeconds) {
throw new UnsupportedOperationException();
}
@Override
public HttpRequest signPutBlob(String container, Blob blob) {
return cleanRequest(processor.createRequest(createMethod, container, blobToObject.apply(blob)));
}
@Override
public HttpRequest signPutBlob(String container, Blob blob, long timeInSeconds) {
throw new UnsupportedOperationException();
}
@Override
public HttpRequest signRemoveBlob(String container, String name) {
return cleanRequest(processor.createRequest(deleteMethod, container, name));
}
@Override
public HttpRequest signGetBlob(String container, String name, org.jclouds.blobstore.options.GetOptions options) {
return cleanRequest(processor.createRequest(getMethod, container, name, blob2HttpGetOptions.apply(options)));
}
}

View File

@ -29,13 +29,11 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.config.BlobStoreMapModule; import org.jclouds.blobstore.config.BlobStoreMapModule;
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi; import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageAsyncBlobStore; import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageAsyncBlobStore;
import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageBlobRequestSigner;
import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageBlobStore; import org.jclouds.hpcloud.objectstorage.blobstore.HPCloudObjectStorageBlobStore;
import org.jclouds.hpcloud.objectstorage.blobstore.functions.HPCloudObjectStorageObjectToBlobMetadata; import org.jclouds.hpcloud.objectstorage.blobstore.functions.HPCloudObjectStorageObjectToBlobMetadata;
import org.jclouds.hpcloud.objectstorage.domain.CDNContainer; import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
@ -107,6 +105,5 @@ public class HPCloudObjectStorageBlobStoreContextModule extends SwiftBlobStoreCo
bind(AsyncBlobStore.class).to(HPCloudObjectStorageAsyncBlobStore.class); bind(AsyncBlobStore.class).to(HPCloudObjectStorageAsyncBlobStore.class);
bind(BlobStore.class).to(HPCloudObjectStorageBlobStore.class); bind(BlobStore.class).to(HPCloudObjectStorageBlobStore.class);
bind(ObjectToBlobMetadata.class).to(HPCloudObjectStorageObjectToBlobMetadata.class); bind(ObjectToBlobMetadata.class).to(HPCloudObjectStorageObjectToBlobMetadata.class);
bind(BlobRequestSigner.class).to(HPCloudObjectStorageBlobRequestSigner.class);
} }
} }

View File

@ -25,10 +25,10 @@ import java.util.Map;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncApi;
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi; import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerAsyncApi; import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncApi;
import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerApi; import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerApi;
import org.jclouds.hpcloud.objectstorage.extensions.CDNContainerAsyncApi;
import org.jclouds.hpcloud.services.HPExtensionCDN; import org.jclouds.hpcloud.services.HPExtensionCDN;
import org.jclouds.hpcloud.services.HPExtensionServiceType; import org.jclouds.hpcloud.services.HPExtensionServiceType;
import org.jclouds.location.suppliers.RegionIdToURISupplier; import org.jclouds.location.suppliers.RegionIdToURISupplier;

View File

@ -1,86 +0,0 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.hpcloud.objectstorage.blobstore;
import static org.testng.Assert.assertEquals;
import java.util.Date;
import java.util.Map;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.hpcloud.objectstorage.internal.BaseHPCloudObjectStorageBlobStoreExpectTest;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
/**
* Tests behavior of {@code HPCloudObjectStorageBlobRequestSigner}
*
* @author Adrian Cole
*/
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "HPCloudObjectStorageBlobRequestSignerTest")
public class HPCloudObjectStorageBlobRequestSignerTest extends BaseHPCloudObjectStorageBlobStoreExpectTest {
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder().put(
keystoneAuthWithUsernameAndPassword, responseWithKeystoneAccess).build();
public void testSignGetBlob() {
BlobRequestSigner signGetBlob = requestsSendResponses(requestResponseMap).getContext().getSigner();
HttpRequest request = signGetBlob.signGetBlob("container", "name");
assertEquals(request.getRequestLine(),
"GET https://objects.jclouds.org/v1.0/40806637803162/container/name HTTP/1.1");
assertEquals(request.getHeaders(), ImmutableMultimap.of("X-Auth-Token", "Auth_4f173437e4b013bee56d1007"));
}
public void testSignRemoveBlob() {
BlobRequestSigner signRemoveBlob = requestsSendResponses(requestResponseMap).getContext().getSigner();
HttpRequest request = signRemoveBlob.signRemoveBlob("container", "name");
assertEquals(request.getRequestLine(),
"DELETE https://objects.jclouds.org/v1.0/40806637803162/container/name HTTP/1.1");
assertEquals(request.getHeaders(), ImmutableMultimap.of("X-Auth-Token", "Auth_4f173437e4b013bee56d1007"));
}
public void testSignPutBlob() {
BlobStore blobStore = requestsSendResponses(requestResponseMap);
BlobRequestSigner signPutBlob = blobStore.getContext().getSigner();
Blob blob = blobStore.blobBuilder("name").forSigning().contentLength(2l).contentMD5(new byte[] { 0, 2, 4, 8 })
.contentType("text/plain").expires(new Date(1000)).build();
HttpRequest request = signPutBlob.signPutBlob("container", blob);
assertEquals(request.getRequestLine(),
"PUT https://objects.jclouds.org/v1.0/40806637803162/container/name HTTP/1.1");
assertEquals(request.getHeaders(), ImmutableMultimap.of("X-Auth-Token", "Auth_4f173437e4b013bee56d1007"));
// TODO:
// assertEquals(request.getPayload(), blob);
}
}

View File

@ -0,0 +1,146 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds 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.hpcloud.objectstorage.blobstore;
import static org.jclouds.openstack.swift.reference.SwiftHeaders.ACCOUNT_TEMPORARY_URL_KEY;
import java.util.Map;
import org.jclouds.apis.ApiMetadata;
import org.jclouds.blobstore.internal.BaseBlobSignerExpectTest;
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApiMetadata;
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApiMetadata.HPCloudObjectStorageTemporaryUrlExtensionModule;
import org.jclouds.hpcloud.objectstorage.blobstore.config.HPCloudObjectStorageBlobStoreContextModule;
import org.jclouds.hpcloud.objectstorage.config.HPCloudObjectStorageRestClientModule;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
import org.jclouds.openstack.swift.config.SwiftRestClientModule.KeystoneStorageEndpointModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
* Tests behavior of {@code SwiftBlobRequestSigner}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "HPCloudObjectStorageBlobSignerExpectTest")
public class HPCloudObjectStorageBlobSignerExpectTest extends BaseBlobSignerExpectTest {
public HPCloudObjectStorageBlobSignerExpectTest() {
identity = "12346637803162:identity";
}
@Override
protected HttpRequest getBlob() {
return HttpRequest.builder().method("GET")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
}
@Override
protected HttpRequest getBlobWithTime() {
return HttpRequest.builder().method("GET")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name?temp_url_sig=fd9b09acbc3ce71182240503c803dda4902098a9&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest getBlobWithOptions() {
return HttpRequest.builder().method("GET")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").addHeader("Range", "bytes=0-1").build();
}
@Override
protected HttpRequest putBlob() {
return HttpRequest.builder().method("PUT")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
}
@Override
protected HttpRequest putBlobWithTime() {
return HttpRequest.builder().method("PUT")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name?temp_url_sig=72e5f6ebafab2b3da0586198797e58fb7478211e&temp_url_expires=123456792").build();
}
@Override
protected HttpRequest removeBlob() {
return HttpRequest.builder().method("DELETE")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/container/name")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
}
/**
* add the keystone commands
*/
@Override
protected Map<HttpRequest, HttpResponse> init() {
HttpRequest authenticate = HttpRequest
.builder()
.method("POST")
.endpoint("https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/tokens")
.addHeader("Accept", "application/json")
.payload(
payloadFromStringWithContentType(
"{\"auth\":{\"passwordCredentials\":{\"username\":\"identity\",\"password\":\"credential\"},\"tenantName\":\"12346637803162\"}}",
"application/json")).build();
HttpResponse authenticationResponse = HttpResponse.builder().statusCode(200)
.payload(payloadFromResourceWithContentType("/keystoneAuthResponseWithCDN.json", "application/json"))
.build();
HttpRequest temporaryKeyRequest = HttpRequest
.builder()
.method("HEAD")
.endpoint("https://objects.jclouds.org/v1.0/40806637803162/")
.addHeader("X-Auth-Token", "Auth_4f173437e4b013bee56d1007").build();
HttpResponse temporaryKeyResponse = HttpResponse.builder().statusCode(200)
.addHeader(ACCOUNT_TEMPORARY_URL_KEY, "TEMPORARY_KEY").build();
return ImmutableMap.<HttpRequest, HttpResponse> builder()
.put(authenticate, authenticationResponse)
.put(temporaryKeyRequest, temporaryKeyResponse).build();
}
@Override
protected ApiMetadata createApiMetadata() {
return new HPCloudObjectStorageApiMetadata().toBuilder()
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
.add(KeystoneStorageEndpointModule.class)
.add(RegionModule.class)
.add(HPCloudObjectStorageRestClientModule.class)
.add(HPCloudObjectStorageBlobStoreContextModule.class)
.add(StaticTimeAndTemporaryUrlKeyModule.class).build()).build();
}
public static class StaticTimeAndTemporaryUrlKeyModule extends HPCloudObjectStorageTemporaryUrlExtensionModule {
public static final long UNIX_EPOCH_TIMESTAMP = 123456789L;
@Override
protected Long unixEpochTimestampProvider() {
return UNIX_EPOCH_TIMESTAMP;
}
}
}

View File

@ -18,7 +18,10 @@
*/ */
package org.jclouds.hpcloud.objectstorage.blobstore.integration; package org.jclouds.hpcloud.objectstorage.blobstore.integration;
import java.io.IOException;
import org.jclouds.openstack.swift.blobstore.integration.SwiftBlobSignerLiveTest; import org.jclouds.openstack.swift.blobstore.integration.SwiftBlobSignerLiveTest;
import org.jclouds.rest.AuthorizationException;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -30,4 +33,20 @@ public class HPCloudObjectStorageBlobSignerLiveTest extends SwiftBlobSignerLiveT
provider = "hpcloud-objectstorage"; provider = "hpcloud-objectstorage";
} }
// hp doesn't yet support time-bound request signing
// https://api-docs.hpcloud.com/hpcloud-object-storage/1.0/content/ch_object-storage-dev-overview.html
@Override
@Test(expectedExceptions = AuthorizationException.class)
public void testSignGetUrlWithTime() throws InterruptedException, IOException {
super.testSignGetUrlWithTime();
}
// hp doesn't yet support time-bound request signing
// https://api-docs.hpcloud.com/hpcloud-object-storage/1.0/content/ch_object-storage-dev-overview.html
@Override
@Test(expectedExceptions = AuthorizationException.class)
public void testSignPutUrlWithTime() throws Exception {
super.testSignPutUrlWithTime();
}
} }