JCLOUDS-457: Created the skeleton of the Glacier API.

This commit is contained in:
Roman C. Coedo 2014-04-22 12:15:03 +02:00 committed by Andrew Gaul
commit d4af465ca8
13 changed files with 819 additions and 0 deletions

128
apis/glacier/pom.xml Normal file
View File

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.jclouds.labs</groupId>
<artifactId>jclouds-labs-aws</artifactId>
<version>1.8.0-SNAPSHOT</version>
</parent>
<groupId>org.apache.jclouds.labs</groupId>
<artifactId>glacier</artifactId>
<name>jclouds glacier api</name>
<description>jclouds components to access an implementation of glacier</description>
<packaging>bundle</packaging>
<properties>
<test.glacier.endpoint>https://glacier.eu-west-1.amazonaws.com</test.glacier.endpoint>
<test.glacier.api-version>2012-06-01</test.glacier.api-version>
<test.glacier.build-version />
<test.glacier.identity>${test.aws.identity}</test.glacier.identity>
<test.glacier.credential>${test.aws.credential}</test.glacier.credential>
<jclouds.osgi.export>org.jclouds.glacier*;version="${project.version}"</jclouds.osgi.export>
<jclouds.osgi.import>
org.jclouds.labs*;version="${project.version}",
org.jclouds*;version="${project.version}",
*
</jclouds.osgi.import>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.jclouds.api</groupId>
<artifactId>sts</artifactId>
<version>${project.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-blobstore</artifactId>
<version>${project.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds</groupId>
<artifactId>jclouds-blobstore</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.jclouds.driver</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.mockwebserver</groupId>
<artifactId>mockwebserver</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemPropertyVariables>
<jclouds.blobstore.httpstream.url>${jclouds.blobstore.httpstream.url}</jclouds.blobstore.httpstream.url>
<jclouds.blobstore.httpstream.md5>${jclouds.blobstore.httpstream.md5}</jclouds.blobstore.httpstream.md5>
<test.glacier.endpoint>${test.glacier.endpoint}</test.glacier.endpoint>
<test.glacier.api-version>${test.glacier.api-version}</test.glacier.api-version>
<test.glacier.build-version>${test.glacier.build-version}</test.glacier.build-version>
<test.glacier.identity>${test.glacier.identity}</test.glacier.identity>
<test.glacier.credential>${test.glacier.credential}</test.glacier.credential>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.reflect.Reflection2.typeToken;
import java.net.URI;
import java.util.Properties;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.glacier.config.GlacierRestClientModule;
import org.jclouds.glacier.reference.GlacierHeaders;
import org.jclouds.rest.internal.BaseRestApiMetadata;
import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.TypeToken;
import com.google.inject.Module;
/**
* Implementation of ApiMetadata for Amazon Glacier API
*
* @author Roman Coedo
*/
public class GlacierApiMetadata extends BaseRestApiMetadata {
@Deprecated
public static final TypeToken<org.jclouds.rest.RestContext<GlacierClient, GlacierAsyncClient>> CONTEXT_TOKEN = new TypeToken<org.jclouds.rest.RestContext<GlacierClient, GlacierAsyncClient>>() {
private static final long serialVersionUID = 1L;
};
private static Builder builder() {
return new Builder();
}
@Override
public Builder toBuilder() {
return builder().fromApiMetadata(this);
}
public GlacierApiMetadata() {
this(builder());
}
protected GlacierApiMetadata(Builder builder) {
super(new Builder());
}
public static Properties defaultProperties() {
Properties properties = BaseRestApiMetadata.defaultProperties();
properties.setProperty(PROPERTY_HEADER_TAG, GlacierHeaders.DEFAULT_AMAZON_HEADERTAG);
return properties;
}
public static class Builder extends BaseRestApiMetadata.Builder<Builder> {
@SuppressWarnings("deprecation")
protected Builder() {
super(GlacierClient.class, GlacierAsyncClient.class);
id("glacier")
.name("Amazon Glacier API")
.identityName("Access Key ID")
.credentialName("Secret Access Key")
.defaultEndpoint("https://glacier.us-east-1.amazonaws.com")
.documentation(URI.create("http://docs.aws.amazon.com/amazonglacier/latest/dev/amazon-glacier-api.html"))
.version("2012-06-01")
.defaultProperties(GlacierApiMetadata.defaultProperties())
.context(CONTEXT_TOKEN)
.view(typeToken(BlobStoreContext.class))
.defaultModules(ImmutableSet.<Class<? extends Module>> of(GlacierRestClientModule.class));
}
@Override
public GlacierApiMetadata build() {
return new GlacierApiMetadata(this);
}
@Override
protected Builder self() {
return this;
}
}
}

View File

@ -0,0 +1,46 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier;
import static org.jclouds.blobstore.attr.BlobScopes.CONTAINER;
import java.io.Closeable;
import java.net.URI;
import javax.inject.Named;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import org.jclouds.blobstore.attr.BlobScope;
import org.jclouds.glacier.filters.RequestAuthorizeSignature;
import org.jclouds.glacier.reference.GlacierHeaders;
import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.RequestFilters;
import com.google.common.util.concurrent.ListenableFuture;
@Headers(keys = GlacierHeaders.VERSION, values = "2012-06-01")
@RequestFilters(RequestAuthorizeSignature.class)
@BlobScope(CONTAINER)
public interface GlacierAsyncClient extends Closeable {
@Named("CreateVault")
@PUT
@Path("/-/vaults/{vault}")
ListenableFuture<URI> createVault(@PathParam("vault") String vaultName);
}

View File

@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier;
import java.io.Closeable;
import java.net.URI;
public interface GlacierClient extends Closeable {
URI createVault(String vaultName);
}

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier.config;
import java.util.concurrent.TimeUnit;
import javax.inject.Named;
import org.jclouds.Constants;
import org.jclouds.date.DateService;
import org.jclouds.date.TimeStamp;
import org.jclouds.glacier.GlacierAsyncClient;
import org.jclouds.glacier.GlacierClient;
import org.jclouds.glacier.filters.RequestAuthorizeSignature;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.config.RestClientModule;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.inject.Provides;
import com.google.inject.Scopes;
@ConfiguresRestClient
public class GlacierRestClientModule extends RestClientModule<GlacierClient, GlacierAsyncClient> {
@Override
protected void configure() {
super.configure();
bind(RequestAuthorizeSignature.class).in(Scopes.SINGLETON);
}
@Provides
@TimeStamp
protected String provideTimeStamp(@TimeStamp Supplier<String> cache) {
return cache.get();
}
@Provides
@TimeStamp
Supplier<String> provideTimeStampCache(@Named(Constants.PROPERTY_SESSION_INTERVAL) long seconds,
final DateService dateService) {
return Suppliers.memoizeWithExpiration(new Supplier<String>() {
@Override
public String get() {
return dateService.iso8601SecondsDateFormat().replaceAll("[-:]", "");
}
}, seconds, TimeUnit.SECONDS);
}
}

View File

@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier.filters;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.TimeStamp;
import org.jclouds.domain.Credentials;
import org.jclouds.glacier.reference.GlacierHeaders;
import org.jclouds.glacier.util.AWSRequestSignerV4;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpRequestFilter;
import org.jclouds.http.HttpUtils;
import org.jclouds.logging.Logger;
import com.google.common.base.Supplier;
import com.google.common.net.HttpHeaders;
@Singleton
public class RequestAuthorizeSignature implements HttpRequestFilter {
private final AWSRequestSignerV4 signer;
@Resource
@Named(Constants.LOGGER_SIGNATURE)
Logger signatureLog = Logger.NULL;
private final Provider<String> timeStampProvider;
private final HttpUtils utils;
@Inject
public RequestAuthorizeSignature(@TimeStamp Provider<String> timeStampProvider,
@org.jclouds.location.Provider Supplier<Credentials> creds, Crypto crypto, HttpUtils utils) {
checkNotNull(creds);
this.signer = new AWSRequestSignerV4(creds.get().identity, creds.get().credential, checkNotNull(crypto));
this.timeStampProvider = checkNotNull(timeStampProvider);
this.utils = checkNotNull(utils);
}
@Override
public HttpRequest filter(HttpRequest request) throws HttpException {
request = request.toBuilder().removeHeader(HttpHeaders.DATE)
.replaceHeader(GlacierHeaders.ALTERNATE_DATE, timeStampProvider.get())
.replaceHeader(HttpHeaders.HOST, request.getEndpoint().getHost()).build();
utils.logRequest(signatureLog, request, ">>");
request = this.signer.sign(request);
utils.logRequest(signatureLog, request, "<<");
return request;
}
}

View File

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier.reference;
public final class GlacierHeaders {
public static final String DEFAULT_AMAZON_HEADERTAG = "amz";
public static final String HEADER_PREFIX = "x-" + DEFAULT_AMAZON_HEADERTAG + "-";
public static final String VERSION = HEADER_PREFIX + "glacier-version";
public static final String ALTERNATE_DATE = HEADER_PREFIX + "date";
private GlacierHeaders() {
}
}

View File

@ -0,0 +1,189 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier.util;
import static com.google.common.base.Charsets.UTF_8;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.util.Locale;
import java.util.Map.Entry;
import javax.crypto.Mac;
import org.jclouds.crypto.Crypto;
import org.jclouds.glacier.reference.GlacierHeaders;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.SortedSetMultimap;
import com.google.common.collect.TreeMultimap;
import com.google.common.hash.Hashing;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
import com.google.common.net.HttpHeaders;
// TODO: Query parameters, not necessary for Glacier
// TODO: Endpoint on buildCredentialScope is being read from the static string. Uncool.
/**
* Signs requests using the AWSv4 signing algorithm
*
* @see <a href="http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html" />
* @author Roman Coedo
*/
public class AWSRequestSignerV4 {
public static final String AUTH_TAG = "AWS4";
public static final String HEADER_TAG = "x-amz-";
public static final String ALGORITHM = AUTH_TAG + "-HMAC-SHA256";
public static final String TERMINATION_STRING = "aws4_request";
public static final String REGION = "us-east-1";
public static final String SERVICE = "glacier";
private final Crypto crypto;
private final String identity;
private final String credential;
public AWSRequestSignerV4(String identity, String credential, Crypto crypto) {
this.crypto = checkNotNull(crypto);
this.identity = checkNotNull(identity);
this.credential = checkNotNull(credential);
}
private static String buildHashedCanonicalRequest(String method, String endpoint, String hashedPayload,
String canonicalizedHeadersString, String signedHeaders) {
return sha256((method + "\n" + endpoint + "\n" + "" + "\n" + canonicalizedHeadersString + "\n" + signedHeaders
+ "\n" + hashedPayload).getBytes());
}
private static String createStringToSign(String date, String credentialScope, String hashedCanonicalRequest) {
return ALGORITHM + "\n" + date + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
}
private static String formatDateWithoutTimestamp(String date) {
return date.substring(0, 8);
}
private static String buildCredentialScope(String dateWithoutTimeStamp) {
return dateWithoutTimeStamp + "/" + REGION + "/" + SERVICE + "/" + TERMINATION_STRING;
}
private static Multimap<String, String> buildCanonicalizedHeadersMap(HttpRequest request) {
Multimap<String, String> headers = request.getHeaders();
SortedSetMultimap<String, String> canonicalizedHeaders = TreeMultimap.create();
for (Entry<String, String> header : headers.entries()) {
if (header.getKey() == null)
continue;
String key = header.getKey().toString().toLowerCase(Locale.getDefault());
// Ignore any headers that are not particularly interesting.
if (key.equalsIgnoreCase(HttpHeaders.CONTENT_TYPE) || key.equalsIgnoreCase(HttpHeaders.CONTENT_MD5)
|| key.equalsIgnoreCase(HttpHeaders.HOST) || key.startsWith(HEADER_TAG)) {
canonicalizedHeaders.put(key, header.getValue());
}
}
return canonicalizedHeaders;
}
private static String buildCanonicalizedHeadersString(Multimap<String, String> canonicalizedHeadersMap) {
StringBuilder canonicalizedHeadersBuffer = new StringBuilder();
for (Entry<String, String> header : canonicalizedHeadersMap.entries()) {
String key = header.getKey();
canonicalizedHeadersBuffer.append(key.toLowerCase()).append(':').append(header.getValue()).append('\n');
}
return canonicalizedHeadersBuffer.toString();
}
private static String buildSignedHeaders(Multimap<String, String> canonicalizedHeadersMap) {
return Joiner.on(';').join(Iterables.transform(canonicalizedHeadersMap.keySet(), new Function<String, String>() {
@Override
public String apply(String input) {
return input.toLowerCase();
}
}));
}
private static String sha256(byte[] unhashedBytes) {
return Hashing.sha256().hashBytes(unhashedBytes).toString();
}
private static String buildHashedPayload(HttpRequest request) {
try {
byte[] unhashedBytes = request.getPayload() == null ? "".getBytes() : ByteStreams.toByteArray(request
.getPayload().getInput());
return sha256(unhashedBytes);
} catch (IOException e) {
throw new HttpException("Error signing request", e);
}
}
private static String buildAuthHeader(String accessKey, String credentialScope, String signedHeaders,
String signature) {
return ALGORITHM + " " + "Credential=" + accessKey + "/" + credentialScope + "," + "SignedHeaders="
+ signedHeaders + "," + "Signature=" + signature;
}
private byte[] hmacSha256(byte[] key, String s) {
try {
Mac hmacSHA256 = crypto.hmacSHA256(key);
return hmacSHA256.doFinal(s.getBytes());
} catch (Exception e) {
throw new HttpException("Error signing request", e);
}
}
private String buildSignature(String dateWithoutTimestamp, String stringToSign) {
byte[] kSecret = (AUTH_TAG + credential).getBytes(UTF_8);
byte[] kDate = hmacSha256(kSecret, dateWithoutTimestamp);
byte[] kRegion = hmacSha256(kDate, REGION);
byte[] kService = hmacSha256(kRegion, SERVICE);
byte[] kSigning = hmacSha256(kService, TERMINATION_STRING);
return BaseEncoding.base16().encode(hmacSha256(kSigning, stringToSign)).toLowerCase();
}
public HttpRequest sign(HttpRequest request) {
// Grab the needed data to build the signature
Multimap<String, String> canonicalizedHeadersMap = buildCanonicalizedHeadersMap(request);
String canonicalizedHeadersString = buildCanonicalizedHeadersString(canonicalizedHeadersMap);
String signedHeaders = buildSignedHeaders(canonicalizedHeadersMap);
String date = request.getFirstHeaderOrNull(GlacierHeaders.ALTERNATE_DATE);
String dateWithoutTimestamp = formatDateWithoutTimestamp(date);
String method = request.getMethod();
String endpoint = request.getEndpoint().getRawPath();
String credentialScope = buildCredentialScope(dateWithoutTimestamp);
String hashedPayload = buildHashedPayload(request);
// Task 1: Create a Canonical Request For Signature Version 4.
String hashedCanonicalRequest = buildHashedCanonicalRequest(method, endpoint, hashedPayload,
canonicalizedHeadersString, signedHeaders);
// Task 2: Create a String to Sign for Signature Version 4.
String stringToSign = createStringToSign(date, credentialScope, hashedCanonicalRequest);
// Task 3: Calculate the AWS Signature Version 4.
String signature = buildSignature(dateWithoutTimestamp, stringToSign);
// Sign the request
String authHeader = buildAuthHeader(identity, credentialScope, signedHeaders, signature);
request = request.toBuilder().replaceHeader(HttpHeaders.AUTHORIZATION, authHeader).build();
return request;
}
}

View File

@ -0,0 +1 @@
org.jclouds.glacier.GlacierApiMetadata

View File

@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier;
import org.jclouds.blobstore.internal.BaseBlobStoreApiMetadataTest;
import org.testng.annotations.Test;
/**
*
* @author Roman Coedo
*/
@Test(groups = "unit", testName = "GlacierApiMetadataTest")
public class GlacierApiMetadataTest extends BaseBlobStoreApiMetadataTest {
public GlacierApiMetadataTest() {
super(new GlacierApiMetadata());
}
}

View File

@ -0,0 +1,77 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier;
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
import static org.jclouds.Constants.PROPERTY_MAX_RETRIES;
import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.Properties;
import java.util.Set;
import org.jclouds.ContextBuilder;
import org.jclouds.concurrent.config.ExecutorServiceModule;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
import com.google.mockwebserver.MockResponse;
import com.google.mockwebserver.MockWebServer;
import com.google.mockwebserver.RecordedRequest;
public class GlacierClientMockTest {
private static final String VAULT_NAME = "ConcreteVaultName";
private static final Set<Module> modules = ImmutableSet.<Module> of(new ExecutorServiceModule(sameThreadExecutor(),
sameThreadExecutor()));
static GlacierClient getGlacierClient(URL server) {
Properties overrides = new Properties();
// prevent expect-100 bug http://code.google.com/p/mockwebserver/issues/detail?id=6
overrides.setProperty(PROPERTY_SO_TIMEOUT, "0");
overrides.setProperty(PROPERTY_MAX_RETRIES, "1");
return ContextBuilder.newBuilder("glacier").credentials("accessKey", "secretKey").endpoint(server.toString())
.modules(modules).overrides(overrides).buildApi(GlacierClient.class);
}
public void testCreateVault() throws IOException, InterruptedException {
// Prepare the response
MockResponse mr = new MockResponse();
mr.setResponseCode(201);
mr.addHeader("x-amzn-RequestId", "AAABZpJrTyioDC_HsOmHae8EZp_uBSJr6cnGOLKp_XJCl-Q");
mr.addHeader("Date", "Sun, 25 Mar 2012 12:02:00 GMT");
mr.addHeader("Location", "/111122223333/vaults/" + VAULT_NAME);
MockWebServer server = new MockWebServer();
server.enqueue(mr);
server.play();
// Send the request and check the response
try {
GlacierClient client = getGlacierClient(server.getUrl("/"));
URI responseUri = client.createVault(VAULT_NAME);
assertEquals(responseUri.toString(), server.getUrl("/") + "111122223333/vaults/" + VAULT_NAME);
RecordedRequest request = server.takeRequest();
assertEquals(request.getRequestLine(), "PUT /-/vaults/" + VAULT_NAME + " HTTP/1.1");
} finally {
server.shutdown();
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.glacier.util;
import static org.testng.Assert.assertEquals;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import org.jclouds.encryption.internal.JCECrypto;
import org.jclouds.http.HttpRequest;
import org.testng.annotations.Test;
import com.google.common.collect.Multimap;
import com.google.common.collect.TreeMultimap;
@Test(groups = "unit", testName = "AWSRequestSignerV4Test")
public class AWSRequestSignerV4Test {
@Test
public void testSignatureCalculation() throws NoSuchAlgorithmException, CertificateException {
String auth = "AWS4-HMAC-SHA256 " + "Credential=AKIAIOSFODNN7EXAMPLE/20120525/us-east-1/glacier/aws4_request,"
+ "SignedHeaders=host;x-amz-date;x-amz-glacier-version,"
+ "Signature=3ce5b2f2fffac9262b4da9256f8d086b4aaf42eba5f111c21681a65a127b7c2a";
String identity = "AKIAIOSFODNN7EXAMPLE";
String credential = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
AWSRequestSignerV4 signer = new AWSRequestSignerV4(identity, credential, new JCECrypto());
HttpRequest request = signer.sign(createRequest());
assertEquals(request.getFirstHeaderOrNull("Authorization"), auth);
}
private HttpRequest createRequest() {
Multimap<String, String> headers = TreeMultimap.create();
headers.put("Host", "glacier.us-east-1.amazonaws.com");
headers.put("x-amz-date", "20120525T002453Z");
headers.put("x-amz-glacier-version", "2012-06-01");
HttpRequest request = HttpRequest.builder().method("PUT")
.endpoint("https://glacier.us-east-1.amazonaws.com/-/vaults/examplevault").headers(headers).build();
return request;
}
}

View File

@ -0,0 +1 @@
org.jclouds.glacier.GlacierApiMetadata