Issue 352: added transient blob signing

This commit is contained in:
Adrian Cole 2010-09-13 22:41:19 -07:00
parent d9820c536a
commit 0e5823afad
5 changed files with 192 additions and 4 deletions

View File

@ -265,7 +265,7 @@ in another application. ex. curl"
(doto (.newBlob blobstore path) (doto (.newBlob blobstore path)
(.setPayload (doto (.setPayload (doto
;; until we pass content md5 ;; until we pass content md5
(PhantomPayload. size nil) (PhantomPayload. (long size) nil)
(.setContentType content-type))))))) (.setContentType content-type)))))))
(defn sign-blob-request (defn sign-blob-request
@ -284,7 +284,7 @@ in another application. ex. curl"
(.. blobstore getContext getSigner) container-name (.. blobstore getContext getSigner) container-name
(doto (.newBlob blobstore path) (doto (.newBlob blobstore path)
(.setPayload (.setPayload
(doto (PhantomPayload. content-length content-md5) (doto (PhantomPayload. (long content-length) content-md5)
(.setContentType content-type)))))))) (.setContentType content-type))))))))
(defn get-blob-stream (defn get-blob-stream

View File

@ -0,0 +1,79 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.filters.BasicAuthentication;
/**
*
* @author Adrian Cole
*/
@Singleton
public class TransientBlobRequestSigner implements BlobRequestSigner {
private final BasicAuthentication basicAuth;
@Inject
public TransientBlobRequestSigner(BasicAuthentication basicAuth) {
this.basicAuth = checkNotNull(basicAuth, "basicAuth");
}
@Override
public HttpRequest signGetBlob(String container, String name) {
HttpRequest request = new HttpRequest("GET", URI.create(String.format("http://localhost/%s/%s", container, name)));
basicAuth.filter(request);
return request;
}
@Override
public HttpRequest signPutBlob(String container, Blob blob) {
HttpRequest request = new HttpRequest("PUT", URI.create(String.format("http://localhost/%s/%s", container, blob
.getMetadata().getName())));
if (blob.getPayload().getContentLength() != null)
request.getHeaders().put(HttpHeaders.CONTENT_LENGTH, blob.getPayload().getContentLength().toString());
if (blob.getPayload().getContentType() != null)
request.getHeaders().put(HttpHeaders.CONTENT_TYPE, blob.getPayload().getContentType());
if (blob.getPayload().getContentMD5() != null)
request.getHeaders().put("Content-MD5", CryptoStreams.base64(blob.getPayload().getContentMD5()));
request.setPayload(blob.getPayload());
basicAuth.filter(request);
return request;
}
@Override
public HttpRequest signRemoveBlob(String container, String name) {
HttpRequest request = new HttpRequest("DELETE", URI.create(String.format("http://localhost/%s/%s", container,
name)));
basicAuth.filter(request);
return request;
}
}

View File

@ -26,9 +26,11 @@ import java.util.concurrent.ConcurrentMap;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.blobstore.AsyncBlobStore; import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext; import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.TransientAsyncBlobStore; import org.jclouds.blobstore.TransientAsyncBlobStore;
import org.jclouds.blobstore.TransientBlobRequestSigner;
import org.jclouds.blobstore.attr.ConsistencyModel; import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.internal.BlobStoreContextImpl; import org.jclouds.blobstore.internal.BlobStoreContextImpl;
@ -68,6 +70,7 @@ public class TransientBlobStoreContextModule extends AbstractModule {
install(new BlobStoreObjectModule()); install(new BlobStoreObjectModule());
install(new BlobStoreMapModule()); install(new BlobStoreMapModule());
bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT); bind(ConsistencyModel.class).toInstance(ConsistencyModel.STRICT);
bind(BlobRequestSigner.class).to(TransientBlobRequestSigner.class);
} }
@Provides @Provides

View File

@ -109,7 +109,7 @@
(download-blob container-name name data-file))) (download-blob container-name name data-file)))
(finally (.delete data-file)))))) (finally (.delete data-file))))))
;; this will fail until transient provider handles signing ;; this will fail until somebody fixes it!
#_ #_
(deftest sing-put-blob-request-test (deftest sing-put-blob-request-test
(let [request (sign-put-blob-request "container" "path" "text/plain" 10)] (let [request (sign-put-blob-request "container" "path" "text/plain" 10)]
@ -117,7 +117,7 @@
(is (= "10" (get "Content-Length" (.getHeaders request)))) (is (= "10" (get "Content-Length" (.getHeaders request))))
(is (= "text/plain" (get "Content-Type" (.getHeaders request)))))) (is (= "text/plain" (get "Content-Type" (.getHeaders request))))))
;; this will fail until transient provider handles signing ;; this will fail until somebody fixes it!
#_ #_
(deftest sing-blob-request-test (deftest sing-blob-request-test
(let [request (sign-blob-request "container" "path" {:method :delete})] (let [request (sign-blob-request "container" "path" {:method :delete})]

View File

@ -0,0 +1,106 @@
/**
*
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.http.HttpRequest;
import org.jclouds.io.payloads.PhantomPayload;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.google.inject.TypeLiteral;
@Test(groups = "unit", testName = "jclouds.TransientBlobRequestSignerTest")
public class TransientBlobRequestSignerTest extends RestClientTest<TransientAsyncBlobStore> {
private BlobRequestSigner signer;
private Factory blobFactory;
public void testSignGetBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
HttpRequest request = signer.signGetBlob("container", "name");
assertRequestLineEquals(request, "GET http://localhost/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Authorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\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 http://localhost/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Authorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\n");
assertPayloadEquals(request, null, null, false);
assertEquals(request.getFilters().size(), 0);
}
public void testSignPutBlob() throws ArrayIndexOutOfBoundsException, SecurityException, IllegalArgumentException,
NoSuchMethodException, IOException {
Blob blob = blobFactory.create(null);
blob.getMetadata().setName("name");
blob.setPayload(new PhantomPayload(2l, new byte[] { 0, 2, 4, 8 }));
blob.getPayload().setContentType("text/plain");
HttpRequest request = signer.signPutBlob("container", blob);
assertRequestLineEquals(request, "PUT http://localhost/container/name HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Authorization: Basic aWRlbnRpdHk6Y3JlZGVudGlhbA==\nContent-Length: 2\nContent-MD5: AAIECA==\nContent-Type: text/plain\n");
assertContentHeadersEqual(request, "text/plain", (long) 2l, new byte[] { 0, 2, 4, 8 });
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);
}
@Override
protected void checkFilters(HttpRequest request) {
}
@Override
public ContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("transient", "identity", "credential", new Properties());
}
@Override
protected TypeLiteral<RestAnnotationProcessor<TransientAsyncBlobStore>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<TransientAsyncBlobStore>>() {
};
}
}