mirror of https://github.com/apache/jclouds.git
Merge pull request #889 from jclouds/issue-1096
Issue 1096: Guice errors when trying to get a signer for a keystone v2 password-auth BlobStore
This commit is contained in:
commit
b49a3d555a
|
@ -22,30 +22,34 @@ import java.net.URI;
|
|||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.blobstore.BlobRequestSigner;
|
||||
import org.jclouds.cloudfiles.blobstore.config.CloudFilesBlobStoreContextModule;
|
||||
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule;
|
||||
import org.jclouds.cloudfiles.config.CloudFilesRestClientModule.StorageAndCDNManagementEndpointModule;
|
||||
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 com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.TypeLiteral;
|
||||
|
||||
/**
|
||||
* Implementation of {@link ApiMetadata} for Rackspace Cloud Files API
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class CloudFilesApiMetadata extends SwiftApiMetadata {
|
||||
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = -1572520638079261710L;
|
||||
|
||||
|
||||
public static final TypeToken<RestContext<CloudFilesClient, CloudFilesAsyncClient>> CONTEXT_TOKEN = new TypeToken<RestContext<CloudFilesClient, CloudFilesAsyncClient>>() {
|
||||
private static final long serialVersionUID = -5070937833892503232L;
|
||||
};
|
||||
|
||||
|
||||
private static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
@ -62,7 +66,7 @@ public class CloudFilesApiMetadata extends SwiftApiMetadata {
|
|||
protected CloudFilesApiMetadata(Builder builder) {
|
||||
super(builder);
|
||||
}
|
||||
|
||||
|
||||
public static Properties defaultProperties() {
|
||||
Properties properties = SwiftApiMetadata.defaultProperties();
|
||||
return properties;
|
||||
|
@ -78,9 +82,13 @@ public class CloudFilesApiMetadata extends SwiftApiMetadata {
|
|||
.documentation(URI.create("http://docs.rackspacecloud.com/files/api/v1/cfdevguide_d5/content/ch01.html"))
|
||||
.defaultProperties(CloudFilesApiMetadata.defaultProperties())
|
||||
.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
|
||||
public CloudFilesApiMetadata build() {
|
||||
return new CloudFilesApiMetadata(this);
|
||||
|
@ -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>>() {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -23,16 +23,12 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.blobstore.BlobRequestSigner;
|
||||
import org.jclouds.cloudfiles.CloudFilesClient;
|
||||
import org.jclouds.openstack.swift.TemporaryUrlKey;
|
||||
import org.jclouds.cloudfiles.blobstore.CloudFilesAsyncBlobStore;
|
||||
import org.jclouds.cloudfiles.blobstore.CloudFilesBlobStore;
|
||||
import org.jclouds.cloudfiles.blobstore.functions.CloudFilesObjectToBlobMetadata;
|
||||
import org.jclouds.cloudfiles.domain.ContainerCDNMetadata;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
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.config.SwiftBlobStoreContextModule;
|
||||
import org.jclouds.openstack.swift.blobstore.functions.ObjectToBlobMetadata;
|
||||
|
@ -70,6 +66,5 @@ public class CloudFilesBlobStoreContextModule extends SwiftBlobStoreContextModul
|
|||
bind(SwiftBlobStore.class).to(CloudFilesBlobStore.class);
|
||||
bind(SwiftAsyncBlobStore.class).to(CloudFilesAsyncBlobStore.class);
|
||||
bind(ObjectToBlobMetadata.class).to(CloudFilesObjectToBlobMetadata.class);
|
||||
bind(BlobRequestSigner.class).to(SwiftBlobRequestSigner.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ import com.google.inject.Provides;
|
|||
import com.google.inject.Scopes;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresRestClient
|
||||
|
@ -53,6 +53,7 @@ public class CloudFilesRestClientModule extends SwiftRestClientModule<CloudFiles
|
|||
.<Class<?>, Class<?>> of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindResolvedClientsToCommonSwift() {
|
||||
bind(CommonSwiftClient.class).to(CloudFilesClient.class).in(Scopes.SINGLETON);
|
||||
bind(CommonSwiftAsyncClient.class).to(CloudFilesAsyncClient.class).in(Scopes.SINGLETON);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -73,7 +73,7 @@ import com.google.inject.assistedinject.FactoryModuleBuilder;
|
|||
|
||||
/**
|
||||
* Configures the Keystone connection.
|
||||
*
|
||||
*
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@ConfiguresRestClient
|
||||
|
@ -88,6 +88,7 @@ public class KeystoneRestClientModule<S extends KeystoneApi, A extends KeystoneA
|
|||
.put(TenantApi.class, TenantAsyncApi.class)
|
||||
.build();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public KeystoneRestClientModule() {
|
||||
super(TypeToken.class.cast(TypeToken.of(KeystoneApi.class)), TypeToken.class.cast(TypeToken.of(KeystoneAsyncApi.class)), DELEGATE_MAP);
|
||||
}
|
||||
|
@ -128,7 +129,7 @@ public class KeystoneRestClientModule<S extends KeystoneApi, A extends KeystoneA
|
|||
bind(ImplicitOptionalConverter.class).to(PresentWhenExtensionAnnotationNamespaceEqualsAnyNamespaceInExtensionsSet.class);
|
||||
super.configure();
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
public Multimap<URI, URI> aliases() {
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ import java.util.Properties;
|
|||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.blobstore.BlobStoreContext;
|
||||
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.StorageEndpointModule;
|
||||
import org.jclouds.rest.RestContext;
|
||||
|
@ -38,13 +39,13 @@ import com.google.inject.Module;
|
|||
|
||||
/**
|
||||
* Implementation of {@link ApiMetadata} for OpenStack Swift
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class SwiftApiMetadata extends BaseRestApiMetadata {
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = 6725672099385580694L;
|
||||
|
||||
|
||||
public static final TypeToken<RestContext<SwiftClient, SwiftAsyncClient>> CONTEXT_TOKEN = new TypeToken<RestContext<SwiftClient, SwiftAsyncClient>>() {
|
||||
private static final long serialVersionUID = -5070937833892503232L;
|
||||
};
|
||||
|
@ -81,7 +82,11 @@ public class SwiftApiMetadata extends BaseRestApiMetadata {
|
|||
.defaultProperties(SwiftApiMetadata.defaultProperties())
|
||||
.view(TypeToken.of(BlobStoreContext.class))
|
||||
.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
|
||||
|
|
|
@ -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.services.ServiceType;
|
||||
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.jclouds.rest.RestContext;
|
||||
|
@ -46,7 +47,7 @@ public class SwiftKeystoneApiMetadata extends SwiftApiMetadata {
|
|||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = 820062881469203616L;
|
||||
|
||||
|
||||
public static final TypeToken<RestContext<SwiftKeystoneClient, SwiftKeystoneAsyncClient>> CONTEXT_TOKEN = new TypeToken<RestContext<SwiftKeystoneClient, SwiftKeystoneAsyncClient>>() {
|
||||
private static final long serialVersionUID = -5070937833892503232L;
|
||||
};
|
||||
|
@ -91,8 +92,12 @@ public class SwiftKeystoneApiMetadata extends SwiftApiMetadata {
|
|||
.defaultEndpoint("http://localhost:5000/v2.0/")
|
||||
.context(CONTEXT_TOKEN)
|
||||
.defaultProperties(SwiftKeystoneApiMetadata.defaultProperties())
|
||||
.defaultModules(ImmutableSet.<Class<? extends Module>>of(KeystoneStorageEndpointModule.class, KeystoneAuthenticationModule.RegionModule.class,
|
||||
SwiftKeystoneRestClientModule.class, SwiftBlobStoreContextModule.class));
|
||||
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
|
||||
.add(KeystoneStorageEndpointModule.class)
|
||||
.add(KeystoneAuthenticationModule.RegionModule.class)
|
||||
.add(SwiftKeystoneRestClientModule.class)
|
||||
.add(SwiftBlobStoreContextModule.class)
|
||||
.add(SwiftKeystoneTemporaryUrlExtensionModule.class).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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.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 java.lang.reflect.Method;
|
||||
|
@ -30,9 +28,6 @@ import java.security.InvalidKeyException;
|
|||
import javax.inject.Inject;
|
||||
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.domain.Blob;
|
||||
import org.jclouds.blobstore.functions.BlobToHttpGetOptions;
|
||||
|
@ -40,21 +35,26 @@ import org.jclouds.crypto.Crypto;
|
|||
import org.jclouds.crypto.CryptoStreams;
|
||||
import org.jclouds.date.TimeStamp;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.http.HttpRequestFilter;
|
||||
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.TemporaryUrlKey;
|
||||
import org.jclouds.openstack.swift.blobstore.functions.BlobToObject;
|
||||
import org.jclouds.openstack.swift.domain.SwiftObject;
|
||||
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
|
||||
*/
|
||||
@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 Provider<Long> unixEpochTimestampProvider;
|
||||
|
@ -67,10 +67,18 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
|
|||
private final Method deleteMethod;
|
||||
private final Method createMethod;
|
||||
|
||||
/**
|
||||
* create a signer for this subtype of swift
|
||||
*
|
||||
* @param processor
|
||||
* bound to the current subclass of {@link CommonSwiftAsyncClient}
|
||||
*/
|
||||
@Inject
|
||||
public SwiftBlobRequestSigner(RestAnnotationProcessor<CommonSwiftAsyncClient> processor, BlobToObject blobToObject,
|
||||
BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto, @TimeStamp Provider<Long> unixEpochTimestampProvider,
|
||||
@TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier) throws SecurityException, NoSuchMethodException {
|
||||
protected SwiftBlobSigner(BlobToObject blobToObject, BlobToHttpGetOptions blob2HttpGetOptions, Crypto crypto,
|
||||
@TimeStamp Provider<Long> unixEpochTimestampProvider,
|
||||
@TemporaryUrlKey Supplier<String> temporaryUrlKeySupplier,
|
||||
RestAnnotationProcessor<T> processor)
|
||||
throws SecurityException, NoSuchMethodException {
|
||||
this.processor = checkNotNull(processor, "processor");
|
||||
this.crypto = checkNotNull(crypto, "crypto");
|
||||
|
||||
|
@ -80,10 +88,9 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
|
|||
this.blobToObject = checkNotNull(blobToObject, "blobToObject");
|
||||
this.blob2HttpGetOptions = checkNotNull(blob2HttpGetOptions, "blob2HttpGetOptions");
|
||||
|
||||
this.getMethod = CommonSwiftAsyncClient.class.getMethod("getObject", String.class, String.class,
|
||||
GetOptions[].class);
|
||||
this.deleteMethod = CommonSwiftAsyncClient.class.getMethod("removeObject", String.class, String.class);
|
||||
this.createMethod = CommonSwiftAsyncClient.class.getMethod("putObject", String.class, SwiftObject.class);
|
||||
this.getMethod = processor.getDeclaring().getMethod("getObject", String.class, String.class, GetOptions[].class);
|
||||
this.deleteMethod = processor.getDeclaring().getMethod("removeObject", String.class, String.class);
|
||||
this.createMethod = processor.getDeclaring().getMethod("putObject", String.class, SwiftObject.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -119,8 +126,7 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
|
|||
}
|
||||
|
||||
private HttpRequest signForTemporaryAccess(HttpRequest request, long timeInSeconds) {
|
||||
HttpRequest.Builder builder = request.toBuilder();
|
||||
builder.filters(filter(request.getFilters(), instanceOf(AuthenticateRequest.class)));
|
||||
HttpRequest.Builder<?> builder = request.toBuilder().filters(ImmutableSet.<HttpRequestFilter>of());
|
||||
|
||||
String key = temporaryUrlKeySupplier.get();
|
||||
if (key == null) {
|
||||
|
@ -128,8 +134,8 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
|
|||
}
|
||||
long expiresInSeconds = unixEpochTimestampProvider.get() + timeInSeconds;
|
||||
|
||||
builder.addQueryParam("temp_url_sig", createSignature(key, createStringToSign(
|
||||
request.getMethod().toUpperCase(), request, expiresInSeconds)));
|
||||
builder.addQueryParam("temp_url_sig",
|
||||
createSignature(key, createStringToSign(request.getMethod().toUpperCase(), request, expiresInSeconds)));
|
||||
builder.addQueryParam("temp_url_expires", "" + expiresInSeconds);
|
||||
|
||||
return builder.build();
|
||||
|
@ -137,14 +143,12 @@ public class SwiftBlobRequestSigner implements BlobRequestSigner {
|
|||
|
||||
private String createStringToSign(String method, HttpRequest request, long expiresInSeconds) {
|
||||
checkArgument(method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("PUT"));
|
||||
return String.format("%s\n%d\n%s", method.toUpperCase(), expiresInSeconds,
|
||||
request.getEndpoint().getPath());
|
||||
return String.format("%s\n%d\n%s", method.toUpperCase(), expiresInSeconds, request.getEndpoint().getPath());
|
||||
}
|
||||
|
||||
private String createSignature(String key, String stringToSign) {
|
||||
try {
|
||||
return CryptoStreams.hex(crypto.hmacSHA1(key.getBytes()).doFinal(stringToSign.getBytes()));
|
||||
|
||||
} catch (InvalidKeyException e) {
|
||||
throw Throwables.propagate(e);
|
||||
}
|
|
@ -18,57 +18,30 @@
|
|||
*/
|
||||
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.BlobRequestSigner;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.attr.ConsistencyModel;
|
||||
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.SwiftBlobRequestSigner;
|
||||
import org.jclouds.openstack.swift.blobstore.SwiftBlobStore;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
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}
|
||||
* bound.
|
||||
* Configures the {@link CloudFilesBlobStoreContext}; requires
|
||||
* {@link SwiftAsyncBlobStore} bound.
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class SwiftBlobStoreContextModule extends AbstractModule {
|
||||
|
||||
@Provides
|
||||
@TimeStamp
|
||||
protected Long unixEpochTimestampProvider() {
|
||||
return System.currentTimeMillis() / 1000; /* convert to seconds */
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
install(new BlobStoreMapModule());
|
||||
bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
|
||||
bind(AsyncBlobStore.class).to(SwiftAsyncBlobStore.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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -11,7 +11,7 @@ import com.google.common.reflect.TypeToken;
|
|||
import com.google.inject.Scopes;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresRestClient
|
||||
|
@ -21,9 +21,9 @@ public class SwiftKeystoneRestClientModule extends SwiftRestClientModule<SwiftKe
|
|||
super(TypeToken.of(SwiftKeystoneClient.class), TypeToken.of(SwiftKeystoneAsyncClient.class), ImmutableMap
|
||||
.<Class<?>, Class<?>> of());
|
||||
}
|
||||
|
||||
|
||||
protected void bindResolvedClientsToCommonSwift() {
|
||||
bind(CommonSwiftClient.class).to(SwiftKeystoneClient.class).in(Scopes.SINGLETON);
|
||||
bind(CommonSwiftAsyncClient.class).to(SwiftKeystoneAsyncClient.class).in(Scopes.SINGLETON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,23 +54,24 @@ import com.google.inject.Provides;
|
|||
import com.google.inject.Scopes;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@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")
|
||||
public SwiftRestClientModule() {
|
||||
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,
|
||||
Map<Class<?>, Class<?>> sync2Async) {
|
||||
Map<Class<?>, Class<?>> sync2Async) {
|
||||
super(syncClientType, asyncClientType, sync2Async);
|
||||
}
|
||||
|
||||
|
||||
public static class StorageEndpointModule extends OpenStackAuthenticationModule {
|
||||
@Provides
|
||||
@Singleton
|
||||
|
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -18,14 +18,12 @@
|
|||
*/
|
||||
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 org.jclouds.http.HttpResponse;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
|
||||
/**
|
||||
* @author Andrei Savu
|
||||
*/
|
||||
|
@ -33,11 +31,6 @@ public class ParseTemporaryUrlKeyFromHeaders implements Function<HttpResponse, S
|
|||
|
||||
@Override
|
||||
public String apply(HttpResponse httpResponse) {
|
||||
Multimap<String, String> headers = httpResponse.getHeaders();
|
||||
if (headers.containsKey(ACCOUNT_TEMPORARY_URL_KEY)) {
|
||||
return getOnlyElement(headers.get(ACCOUNT_TEMPORARY_URL_KEY));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return httpResponse.getFirstHeaderOrNull(ACCOUNT_TEMPORARY_URL_KEY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,33 +21,32 @@ package org.jclouds.openstack.swift;
|
|||
import static org.jclouds.Constants.PROPERTY_API_VERSION;
|
||||
import static org.jclouds.Constants.PROPERTY_ENDPOINT;
|
||||
import static org.jclouds.location.reference.LocationConstants.PROPERTY_REGIONS;
|
||||
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
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.date.TimeStamp;
|
||||
import org.jclouds.blobstore.BlobRequestSigner;
|
||||
import org.jclouds.http.HttpRequest;
|
||||
import org.jclouds.openstack.functions.URIFromAuthenticationResponseForService;
|
||||
import org.jclouds.openstack.internal.TestOpenStackAuthenticationModule;
|
||||
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.TemporaryUrlExtensionModule;
|
||||
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.RestAnnotationProcessor;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
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}
|
||||
|
@ -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
|
||||
protected Long unixEpochTimestampProvider() {
|
||||
return UNIX_EPOCH_TIMESTAMP;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureTemporaryUrlExtension() {
|
||||
bindClientAndAsyncClient(binder(), TemporaryUrlKeyApi.class, TemporaryUrlKeyAsyncApi.class);
|
||||
protected void configure() {
|
||||
bindTemporaryUrlKeyApi();
|
||||
bind(new TypeLiteral<Supplier<String>>() {
|
||||
}).annotatedWith(TemporaryUrlKey.class).toInstance(Suppliers.ofInstance(TEMPORARY_URL_KEY));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindRequestSigner() {
|
||||
bind(BlobRequestSigner.class).to(new TypeLiteral<SwiftBlobSigner<SwiftAsyncClient>>() {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ApiMetadata createApiMetadata() {
|
||||
return new SwiftApiMetadata().toBuilder().defaultModules(
|
||||
ImmutableSet.<Class<? extends Module>>of(StorageEndpointModule.class, SwiftRestClientModule.class,
|
||||
StaticTimeAndTemporaryUrlKeyModule.class)).build();
|
||||
return new SwiftApiMetadata().toBuilder()
|
||||
.defaultModules(ImmutableSet.<Class<? extends Module>>builder()
|
||||
.add(StorageEndpointModule.class)
|
||||
.add(SwiftRestClientModule.class)
|
||||
.add(SwiftBlobStoreContextModule.class)
|
||||
.add(StaticTimeAndTemporaryUrlKeyModule.class).build()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -19,18 +19,13 @@
|
|||
package org.jclouds.openstack.swift.blobstore.integration;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.jclouds.blobstore.integration.internal.BaseBlobLiveTest;
|
||||
import org.jclouds.openstack.keystone.v2_0.config.KeystoneProperties;
|
||||
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author James Murty
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
|
@ -42,7 +37,7 @@ public class SwiftBlobLiveTest extends BaseBlobLiveTest {
|
|||
setIfTestSystemPropertyPresent(props, KeystoneProperties.CREDENTIAL_TYPE);
|
||||
return props;
|
||||
}
|
||||
|
||||
|
||||
public SwiftBlobLiveTest() {
|
||||
provider = System.getProperty("test.swift.provider", "swift");
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.concurrent.ExecutorService;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.HeaderParam;
|
||||
|
||||
import org.jclouds.Constants;
|
||||
import org.jclouds.blobstore.LocalAsyncBlobStore;
|
||||
|
@ -61,11 +60,10 @@ import com.google.common.base.Throwables;
|
|||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
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.
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@Singleton
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -26,8 +26,6 @@ import org.jclouds.io.ContentMetadataBuilder;
|
|||
import org.jclouds.io.MutableContentMetadata;
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
|
|
|
@ -169,7 +169,7 @@ import com.google.inject.util.Types;
|
|||
|
||||
/**
|
||||
* Creates http methods based on annotations on a class or interface.
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class RestAnnotationProcessor<T> {
|
||||
|
@ -192,7 +192,7 @@ public class RestAnnotationProcessor<T> {
|
|||
static final LoadingCache<Method, LoadingCache<Integer, Set<Annotation>>> methodToIndexOfParamToPostParamAnnotations = createMethodToIndexOfParamToAnnotation(PayloadParam.class);
|
||||
static final LoadingCache<Method, LoadingCache<Integer, Set<Annotation>>> methodToIndexOfParamToPartParamAnnotations = createMethodToIndexOfParamToAnnotation(PartParam.class);
|
||||
static final LoadingCache<Method, LoadingCache<Integer, Set<Annotation>>> methodToIndexOfParamToParamParserAnnotations = createMethodToIndexOfParamToAnnotation(ParamParser.class);
|
||||
|
||||
|
||||
final Cache<MethodKey, Method> delegationMap;
|
||||
|
||||
static LoadingCache<Method, LoadingCache<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
|
||||
|
@ -322,7 +322,7 @@ public class RestAnnotationProcessor<T> {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Inject
|
||||
public RestAnnotationProcessor(Injector injector, LoadingCache<Class<?>, Boolean> seedAnnotationCache, Cache<MethodKey, Method> delegationMap,
|
||||
public RestAnnotationProcessor(Injector injector, LoadingCache<Class<?>, Boolean> seedAnnotationCache, Cache<MethodKey, Method> delegationMap,
|
||||
@ApiVersion String apiVersion, @BuildVersion String buildVersion, ParseSax.Factory parserFactory,
|
||||
HttpUtils utils, ContentMetadataCodec contentMetadataCodec, TypeLiteral<T> typeLiteral) throws ExecutionException {
|
||||
this.declaring = (Class<T>) typeLiteral.getRawType();
|
||||
|
@ -343,7 +343,7 @@ public class RestAnnotationProcessor<T> {
|
|||
this.buildVersion = buildVersion;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Method getDelegateOrNull(Method in) {
|
||||
return delegationMap.getIfPresent(new MethodKey(in));
|
||||
}
|
||||
|
@ -364,7 +364,7 @@ public class RestAnnotationProcessor<T> {
|
|||
&& Objects.equal(this.name, that.name)
|
||||
&& Objects.equal(this.parametersTypeHashCode, that.parametersTypeHashCode);
|
||||
}
|
||||
|
||||
|
||||
private final String name;
|
||||
private final int parametersTypeHashCode;
|
||||
private final Class<?> declaringClass;
|
||||
|
@ -838,7 +838,7 @@ public class RestAnnotationProcessor<T> {
|
|||
Type returnVal = getReturnTypeForMethod(method);
|
||||
return getJsonParserKeyForMethodAnType(method, returnVal);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Key<? extends Function<HttpResponse, ?>> getJAXBParserKeyForMethod(Method method) {
|
||||
Type returnVal = getReturnTypeForMethod(method);
|
||||
|
@ -1334,4 +1334,10 @@ public class RestAnnotationProcessor<T> {
|
|||
return postParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* the class that is being processed
|
||||
*/
|
||||
public Class<T> getDeclaring(){
|
||||
return declaring;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,30 +18,38 @@
|
|||
*/
|
||||
package org.jclouds.hpcloud.objectstorage;
|
||||
|
||||
import static org.jclouds.rest.config.BinderUtils.bindClientAndAsyncClient;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.jclouds.apis.ApiMetadata;
|
||||
import org.jclouds.blobstore.BlobRequestSigner;
|
||||
import org.jclouds.hpcloud.objectstorage.blobstore.config.HPCloudObjectStorageBlobStoreContextModule;
|
||||
import org.jclouds.hpcloud.objectstorage.config.HPCloudObjectStorageRestClientModule;
|
||||
import org.jclouds.openstack.keystone.v2_0.config.KeystoneAuthenticationModule.RegionModule;
|
||||
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.extensions.KeystoneTemporaryUrlKeyAsyncApi;
|
||||
import org.jclouds.openstack.swift.extensions.TemporaryUrlKeyApi;
|
||||
import org.jclouds.rest.RestContext;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.TypeLiteral;
|
||||
/**
|
||||
* Implementation of {@link org.jclouds.providers.ProviderMetadata} for HP Cloud Services Object Storage
|
||||
*
|
||||
*
|
||||
* @author Jeremy Daggett
|
||||
*/
|
||||
public class HPCloudObjectStorageApiMetadata extends SwiftKeystoneApiMetadata {
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = 820062881469203616L;
|
||||
|
||||
|
||||
public static final TypeToken<RestContext<HPCloudObjectStorageApi, HPCloudObjectStorageAsyncApi>> CONTEXT_TOKEN = new TypeToken<RestContext<HPCloudObjectStorageApi, HPCloudObjectStorageAsyncApi>>() {
|
||||
private static final long serialVersionUID = -5070937833892503232L;
|
||||
};
|
||||
|
@ -82,7 +90,8 @@ public class HPCloudObjectStorageApiMetadata extends SwiftKeystoneApiMetadata {
|
|||
.add(KeystoneStorageEndpointModule.class)
|
||||
.add(RegionModule.class)
|
||||
.add(HPCloudObjectStorageRestClientModule.class)
|
||||
.add(HPCloudObjectStorageBlobStoreContextModule.class).build());
|
||||
.add(HPCloudObjectStorageBlobStoreContextModule.class)
|
||||
.add(HPCloudObjectStorageTemporaryUrlExtensionModule.class).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -96,4 +105,24 @@ public class HPCloudObjectStorageApiMetadata extends SwiftKeystoneApiMetadata {
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -29,13 +29,11 @@ import javax.inject.Inject;
|
|||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.blobstore.AsyncBlobStore;
|
||||
import org.jclouds.blobstore.BlobRequestSigner;
|
||||
import org.jclouds.blobstore.BlobStore;
|
||||
import org.jclouds.blobstore.attr.ConsistencyModel;
|
||||
import org.jclouds.blobstore.config.BlobStoreMapModule;
|
||||
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageApi;
|
||||
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.functions.HPCloudObjectStorageObjectToBlobMetadata;
|
||||
import org.jclouds.hpcloud.objectstorage.domain.CDNContainer;
|
||||
|
@ -53,7 +51,7 @@ import com.google.common.cache.LoadingCache;
|
|||
import com.google.inject.Provides;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class HPCloudObjectStorageBlobStoreContextModule extends SwiftBlobStoreContextModule {
|
||||
|
@ -99,7 +97,7 @@ public class HPCloudObjectStorageBlobStoreContextModule extends SwiftBlobStoreCo
|
|||
protected LoadingCache<String, URI> cdnContainer(GetCDNMetadata loader) {
|
||||
return CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build(loader);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
install(new BlobStoreMapModule());
|
||||
|
@ -107,6 +105,5 @@ public class HPCloudObjectStorageBlobStoreContextModule extends SwiftBlobStoreCo
|
|||
bind(AsyncBlobStore.class).to(HPCloudObjectStorageAsyncBlobStore.class);
|
||||
bind(BlobStore.class).to(HPCloudObjectStorageBlobStore.class);
|
||||
bind(ObjectToBlobMetadata.class).to(HPCloudObjectStorageObjectToBlobMetadata.class);
|
||||
bind(BlobRequestSigner.class).to(HPCloudObjectStorageBlobRequestSigner.class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ import java.util.Map;
|
|||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.jclouds.hpcloud.objectstorage.HPCloudObjectStorageAsyncApi;
|
||||
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.CDNContainerAsyncApi;
|
||||
import org.jclouds.hpcloud.services.HPExtensionCDN;
|
||||
import org.jclouds.hpcloud.services.HPExtensionServiceType;
|
||||
import org.jclouds.location.suppliers.RegionIdToURISupplier;
|
||||
|
@ -45,7 +45,7 @@ import com.google.inject.Provides;
|
|||
import com.google.inject.Scopes;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
@ConfiguresRestClient
|
||||
|
@ -63,7 +63,7 @@ public class HPCloudObjectStorageRestClientModule extends
|
|||
bind(CommonSwiftClient.class).to(HPCloudObjectStorageApi.class).in(Scopes.SINGLETON);
|
||||
bind(CommonSwiftAsyncClient.class).to(HPCloudObjectStorageAsyncApi.class).in(Scopes.SINGLETON);
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@HPExtensionCDN
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,10 @@
|
|||
*/
|
||||
package org.jclouds.hpcloud.objectstorage.blobstore.integration;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.jclouds.openstack.swift.blobstore.integration.SwiftBlobSignerLiveTest;
|
||||
import org.jclouds.rest.AuthorizationException;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
|
@ -30,4 +33,20 @@ public class HPCloudObjectStorageBlobSignerLiveTest extends SwiftBlobSignerLiveT
|
|||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue