Skip to content

Commit e5c6f94

Browse files
committed
Merge pull request #77 from aozarov/master
Add signURL functionality
2 parents c64b3d7 + 9955998 commit e5c6f94

File tree

13 files changed

+306
-27
lines changed

13 files changed

+306
-27
lines changed

gcloud-java-core/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@
2828
<dependency>
2929
<groupId>com.google.http-client</groupId>
3030
<artifactId>google-http-client</artifactId>
31-
<version>1.19.0</version>
31+
<version>1.20.0</version>
3232
<scope>compile</scope>
3333
</dependency>
3434
<dependency>
3535
<groupId>com.google.oauth-client</groupId>
3636
<artifactId>google-oauth-client</artifactId>
37-
<version>1.19.0</version>
37+
<version>1.20.0</version>
3838
<scope>compile</scope>
3939
</dependency>
4040
<dependency>

gcloud-java-core/src/main/java/com/google/gcloud/AuthCredentials.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ private Object readResolve() throws ObjectStreamException {
6262
}
6363
}
6464

65-
private static class ServiceAccountAuthCredentials extends AuthCredentials {
65+
public static class ServiceAccountAuthCredentials extends AuthCredentials {
6666

6767
private static final long serialVersionUID = 8007708734318445901L;
6868
private final String account;
@@ -94,6 +94,14 @@ protected HttpRequestInitializer httpRequestInitializer(
9494
return builder.build();
9595
}
9696

97+
public String account() {
98+
return account;
99+
}
100+
101+
public PrivateKey privateKey() {
102+
return privateKey;
103+
}
104+
97105
@Override
98106
public int hashCode() {
99107
return Objects.hash(account, privateKey);
@@ -187,7 +195,7 @@ public static AuthCredentials createApplicationDefaults() throws IOException {
187195
return new ApplicationDefaultAuthCredentials();
188196
}
189197

190-
public static AuthCredentials createFor(String account, PrivateKey privateKey) {
198+
public static ServiceAccountAuthCredentials createFor(String account, PrivateKey privateKey) {
191199
return new ServiceAccountAuthCredentials(account, privateKey);
192200
}
193201

gcloud-java-examples/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,15 @@
2121
<version>${project.version}</version>
2222
</dependency>
2323
</dependencies>
24+
<build>
25+
<plugins>
26+
<plugin>
27+
<groupId>org.codehaus.mojo</groupId>
28+
<artifactId>exec-maven-plugin</artifactId>
29+
<configuration>
30+
<skip>false</skip>
31+
</configuration>
32+
</plugin>
33+
</plugins>
34+
</build>
2435
</project>

gcloud-java-examples/src/main/java/com/google/gcloud/examples/StorageExample.java

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.gcloud.examples;
1818

19+
import com.google.gcloud.AuthCredentials;
20+
import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials;
1921
import com.google.gcloud.RetryParams;
2022
import com.google.gcloud.spi.StorageRpc.Tuple;
2123
import com.google.gcloud.storage.BatchRequest;
@@ -27,6 +29,7 @@
2729
import com.google.gcloud.storage.StorageService;
2830
import com.google.gcloud.storage.StorageService.ComposeRequest;
2931
import com.google.gcloud.storage.StorageService.CopyRequest;
32+
import com.google.gcloud.storage.StorageService.SignUrlOption;
3033
import com.google.gcloud.storage.StorageServiceFactory;
3134
import com.google.gcloud.storage.StorageServiceOptions;
3235

@@ -40,7 +43,14 @@
4043
import java.nio.file.Files;
4144
import java.nio.file.Path;
4245
import java.nio.file.Paths;
46+
import java.security.KeyStore;
47+
import java.security.KeyStoreException;
48+
import java.security.NoSuchAlgorithmException;
49+
import java.security.PrivateKey;
50+
import java.security.UnrecoverableKeyException;
51+
import java.security.cert.CertificateException;
4352
import java.util.Arrays;
53+
import java.util.Calendar;
4454
import java.util.HashMap;
4555
import java.util.Map;
4656

@@ -58,7 +68,8 @@
5868
* -Dexec.args="[<project_id>] list [<bucket>]| info [<bucket> [<file>]]|
5969
* download <bucket> <path> [local_file]| upload <local_file> <bucket> [<path>]|
6070
* delete <bucket> <path>+| cp <from_bucket> <from_path> <to_bucket> <to_path>|
61-
* compose <bucket> <from_path>+ <to_path>| update_metadata <bucket> <file> [key=value]*"}
71+
* compose <bucket> <from_path>+ <to_path>| update_metadata <bucket> <file> [key=value]*|
72+
* sign_url <service_account_private_key_file> <service_account_email> <bucket> <path>"}
6273
* </li>
6374
* </ol>
6475
*
@@ -75,7 +86,7 @@ private static abstract class StorageAction<T> {
7586

7687
abstract void run(StorageService storage, T request) throws Exception;
7788

78-
abstract T parse(String... args) throws IllegalArgumentException, IOException;
89+
abstract T parse(String... args) throws Exception;
7990

8091
protected String params() {
8192
return "";
@@ -424,7 +435,7 @@ public String params() {
424435
*
425436
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/update">Objects: update</a>
426437
*/
427-
private static class UpdateMetadata extends StorageAction<Tuple<Blob, Map<String, String>>> {
438+
private static class UpdateMetadataAction extends StorageAction<Tuple<Blob, Map<String, String>>> {
428439

429440
@Override
430441
public void run(StorageService storage, Tuple<Blob, Map<String, String>> tuple)
@@ -467,6 +478,52 @@ public String params() {
467478
}
468479
}
469480

481+
/**
482+
* This class demonstrates how to sign a url.
483+
* URL will be valid for 1 day.
484+
*
485+
* @see <a href="https://cloud.google.com/storage/docs/access-control#Signed-URLs">Signed URLs</a>
486+
*/
487+
private static class SignUrlAction extends
488+
StorageAction<Tuple<ServiceAccountAuthCredentials, Blob>> {
489+
490+
private static final char[] PASSWORD = "notasecret".toCharArray();
491+
492+
@Override
493+
public void run(StorageService storage, Tuple<ServiceAccountAuthCredentials, Blob> tuple)
494+
throws Exception {
495+
run(storage, tuple.x(), tuple.y());
496+
}
497+
498+
private void run(StorageService storage, ServiceAccountAuthCredentials cred, Blob blob)
499+
throws IOException {
500+
Calendar cal = Calendar.getInstance();
501+
cal.add(Calendar.DATE, 1);
502+
long expiration = cal.getTimeInMillis() / 1000;
503+
System.out.println("Signed URL: " +
504+
storage.signUrl(blob, expiration, SignUrlOption.serviceAccount(cred)));
505+
}
506+
507+
@Override
508+
Tuple<ServiceAccountAuthCredentials, Blob> parse(String... args)
509+
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException,
510+
UnrecoverableKeyException {
511+
if (args.length != 4) {
512+
throw new IllegalArgumentException();
513+
}
514+
KeyStore keystore = KeyStore.getInstance("PKCS12");
515+
keystore.load(Files.newInputStream(Paths.get(args[0])), PASSWORD);
516+
PrivateKey privateKey = (PrivateKey) keystore.getKey("privatekey", PASSWORD);
517+
ServiceAccountAuthCredentials cred = AuthCredentials.createFor(args[1], privateKey);
518+
return Tuple.of(cred, Blob.of(args[2], args[3]));
519+
}
520+
521+
@Override
522+
public String params() {
523+
return "<service_account_private_key_file> <service_account_email> <bucket> <path>";
524+
}
525+
}
526+
470527
static {
471528
ACTIONS.put("info", new InfoAction());
472529
ACTIONS.put("delete", new DeleteAction());
@@ -475,7 +532,8 @@ public String params() {
475532
ACTIONS.put("download", new DownloadAction());
476533
ACTIONS.put("cp", new CopyAction());
477534
ACTIONS.put("compose", new ComposeAction());
478-
ACTIONS.put("update_metadata", new UpdateMetadata());
535+
ACTIONS.put("update_metadata", new UpdateMetadataAction());
536+
ACTIONS.put("sign_url", new SignUrlAction());
479537
}
480538

481539
public static void printUsage() {

gcloud-java-storage/src/main/java/com/google/gcloud/spi/DefaultStorageRpc.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ public DefaultStorageRpc(StorageServiceOptions options) {
8282
HttpRequestInitializer initializer = options.httpRequestInitializer();
8383
this.options = options;
8484
storage = new Storage.Builder(transport, new JacksonFactory(), initializer)
85+
.setRootUrl(options.host())
8586
.setApplicationName("gcloud-java")
8687
.build();
87-
// Todo: make sure nulls are being used as Data.asNull()
8888
}
8989

9090
private static StorageServiceException translate(IOException exception) {

gcloud-java-storage/src/main/java/com/google/gcloud/spi/StorageRpc.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
/* * Copyright 2015 Google Inc. All Rights Reserved. * * 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 com.google.gcloud.spi;import com.google.api.services.storage.model.Bucket;import com.google.api.services.storage.model.StorageObject;import com.google.common.collect.ImmutableList;import com.google.common.collect.ImmutableMap;import com.google.gcloud.storage.StorageServiceException;import java.util.List;import java.util.Map;public interface StorageRpc { enum Option { PREDEFINED_ACL("predefinedAcl"), PREDEFINED_DEFAULT_OBJECT_ACL("predefinedDefaultObjectAcl"), IF_METAGENERATION_MATCH("ifMetagenerationMatch"), IF_METAGENERATION_NOT_MATCH("ifMetagenerationNotMatch"), IF_GENERATION_NOT_MATCH("ifGenerationMatch"), IF_GENERATION_MATCH("ifGenerationNotMatch"), IF_SOURCE_METAGENERATION_MATCH("ifSourceMetagenerationMatch"), IF_SOURCE_METAGENERATION_NOT_MATCH("ifSourceMetagenerationNotMatch"), IF_SOURCE_GENERATION_MATCH("ifSourceGenerationMatch"), IF_SOURCE_GENERATION_NOT_MATCH("ifSourceGenerationNotMatch"), PREFIX("prefix"), MAX_RESULTS("maxResults"), PAGE_TOKEN("pageToken"), DELIMITER("delimiter"), VERSIONS("versions"); private final String value; Option(String value) { this.value = value; } public String value() { return value; } @SuppressWarnings("unchecked") <T> T get(Map<Option, ?> options) { return (T) options.get(this); } String getString(Map<Option, ?> options) { return get(options); } Long getLong(Map<Option, ?> options) { return get(options); } Boolean getBoolean(Map<Option, ?> options) { return get(options); } } class Tuple<X, Y> { private final X x; private final Y y; private Tuple(X x, Y y) { this.x = x; this.y = y; } public static <X, Y> Tuple<X, Y> of(X x, Y y) { return new Tuple<>(x, y); } public X x() { return x; } public Y y() { return y; } } class BatchRequest { public final List<Tuple<StorageObject, Map<Option, ?>>> toDelete; public final List<Tuple<StorageObject, Map<Option, ?>>> toUpdate; public final List<Tuple<StorageObject, Map<Option, ?>>> toGet; public BatchRequest(Iterable<Tuple<StorageObject, Map<Option, ?>>> toDelete, Iterable<Tuple<StorageObject, Map<Option, ?>>> toUpdate, Iterable<Tuple<StorageObject, Map<Option, ?>>> toGet) { this.toDelete = ImmutableList.copyOf(toDelete); this.toUpdate = ImmutableList.copyOf(toUpdate); this.toGet = ImmutableList.copyOf(toGet); } } class BatchResponse { public final Map<StorageObject, Tuple<Boolean, StorageServiceException>> deletes; public final Map<StorageObject, Tuple<StorageObject, StorageServiceException>> updates; public final Map<StorageObject, Tuple<StorageObject, StorageServiceException>> gets; public BatchResponse(Map<StorageObject, Tuple<Boolean, StorageServiceException>> deletes, Map<StorageObject, Tuple<StorageObject, StorageServiceException>> updates, Map<StorageObject, Tuple<StorageObject, StorageServiceException>> gets) { this.deletes = ImmutableMap.copyOf(deletes); this.updates = ImmutableMap.copyOf(updates); this.gets = ImmutableMap.copyOf(gets); } } Bucket create(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; StorageObject create(StorageObject object, byte[] content, Map<Option, ?> options) throws StorageServiceException; Tuple<String, Iterable<Bucket>> list(Map<Option, ?> options) throws StorageServiceException; Tuple<String, Iterable<StorageObject>> list(String bucket, Map<Option, ?> options) throws StorageServiceException; Bucket get(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; StorageObject get(StorageObject object, Map<Option, ?> options) throws StorageServiceException; Bucket patch(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; StorageObject patch(StorageObject storageObject, Map<Option, ?> options) throws StorageServiceException; boolean delete(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; boolean delete(StorageObject object, Map<Option, ?> options) throws StorageServiceException; BatchResponse batch(BatchRequest request) throws StorageServiceException; StorageObject compose(Iterable<StorageObject> sources, StorageObject target, Map<Option, ?> targetOptions) throws StorageServiceException; StorageObject copy(StorageObject source, Map<Option, ?> sourceOptions, StorageObject target, Map<Option, ?> targetOptions) throws StorageServiceException; byte[] load(StorageObject storageObject, Map<Option, ?> options) throws StorageServiceException; byte[] read(StorageObject from, Map<Option, ?> options, long position, int bytes) throws StorageServiceException; String open(StorageObject object, Map<Option, ?> options) throws StorageServiceException; void write(String uploadId, byte[] toWrite, int toWriteOffset, StorageObject dest, long destOffset, int length, boolean last) throws StorageServiceException;}
1+
/* * Copyright 2015 Google Inc. All Rights Reserved. * * 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 com.google.gcloud.spi;import com.google.api.services.storage.model.Bucket;import com.google.api.services.storage.model.StorageObject;import com.google.common.collect.ImmutableList;import com.google.common.collect.ImmutableMap;import com.google.gcloud.storage.StorageServiceException;import java.util.List;import java.util.Map;public interface StorageRpc { // These options are part of the Google Cloud storage header options enum Option { PREDEFINED_ACL("predefinedAcl"), PREDEFINED_DEFAULT_OBJECT_ACL("predefinedDefaultObjectAcl"), IF_METAGENERATION_MATCH("ifMetagenerationMatch"), IF_METAGENERATION_NOT_MATCH("ifMetagenerationNotMatch"), IF_GENERATION_NOT_MATCH("ifGenerationMatch"), IF_GENERATION_MATCH("ifGenerationNotMatch"), IF_SOURCE_METAGENERATION_MATCH("ifSourceMetagenerationMatch"), IF_SOURCE_METAGENERATION_NOT_MATCH("ifSourceMetagenerationNotMatch"), IF_SOURCE_GENERATION_MATCH("ifSourceGenerationMatch"), IF_SOURCE_GENERATION_NOT_MATCH("ifSourceGenerationNotMatch"), PREFIX("prefix"), MAX_RESULTS("maxResults"), PAGE_TOKEN("pageToken"), DELIMITER("delimiter"), VERSIONS("versions"); private final String value; Option(String value) { this.value = value; } public String value() { return value; } @SuppressWarnings("unchecked") <T> T get(Map<Option, ?> options) { return (T) options.get(this); } String getString(Map<Option, ?> options) { return get(options); } Long getLong(Map<Option, ?> options) { return get(options); } Boolean getBoolean(Map<Option, ?> options) { return get(options); } } class Tuple<X, Y> { private final X x; private final Y y; private Tuple(X x, Y y) { this.x = x; this.y = y; } public static <X, Y> Tuple<X, Y> of(X x, Y y) { return new Tuple<>(x, y); } public X x() { return x; } public Y y() { return y; } } class BatchRequest { public final List<Tuple<StorageObject, Map<Option, ?>>> toDelete; public final List<Tuple<StorageObject, Map<Option, ?>>> toUpdate; public final List<Tuple<StorageObject, Map<Option, ?>>> toGet; public BatchRequest(Iterable<Tuple<StorageObject, Map<Option, ?>>> toDelete, Iterable<Tuple<StorageObject, Map<Option, ?>>> toUpdate, Iterable<Tuple<StorageObject, Map<Option, ?>>> toGet) { this.toDelete = ImmutableList.copyOf(toDelete); this.toUpdate = ImmutableList.copyOf(toUpdate); this.toGet = ImmutableList.copyOf(toGet); } } class BatchResponse { public final Map<StorageObject, Tuple<Boolean, StorageServiceException>> deletes; public final Map<StorageObject, Tuple<StorageObject, StorageServiceException>> updates; public final Map<StorageObject, Tuple<StorageObject, StorageServiceException>> gets; public BatchResponse(Map<StorageObject, Tuple<Boolean, StorageServiceException>> deletes, Map<StorageObject, Tuple<StorageObject, StorageServiceException>> updates, Map<StorageObject, Tuple<StorageObject, StorageServiceException>> gets) { this.deletes = ImmutableMap.copyOf(deletes); this.updates = ImmutableMap.copyOf(updates); this.gets = ImmutableMap.copyOf(gets); } } Bucket create(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; StorageObject create(StorageObject object, byte[] content, Map<Option, ?> options) throws StorageServiceException; Tuple<String, Iterable<Bucket>> list(Map<Option, ?> options) throws StorageServiceException; Tuple<String, Iterable<StorageObject>> list(String bucket, Map<Option, ?> options) throws StorageServiceException; Bucket get(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; StorageObject get(StorageObject object, Map<Option, ?> options) throws StorageServiceException; Bucket patch(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; StorageObject patch(StorageObject storageObject, Map<Option, ?> options) throws StorageServiceException; boolean delete(Bucket bucket, Map<Option, ?> options) throws StorageServiceException; boolean delete(StorageObject object, Map<Option, ?> options) throws StorageServiceException; BatchResponse batch(BatchRequest request) throws StorageServiceException; StorageObject compose(Iterable<StorageObject> sources, StorageObject target, Map<Option, ?> targetOptions) throws StorageServiceException; StorageObject copy(StorageObject source, Map<Option, ?> sourceOptions, StorageObject target, Map<Option, ?> targetOptions) throws StorageServiceException; byte[] load(StorageObject storageObject, Map<Option, ?> options) throws StorageServiceException; byte[] read(StorageObject from, Map<Option, ?> options, long position, int bytes) throws StorageServiceException; String open(StorageObject object, Map<Option, ?> options) throws StorageServiceException; void write(String uploadId, byte[] toWrite, int toWriteOffset, StorageObject dest, long destOffset, int length, boolean last) throws StorageServiceException;}

0 commit comments

Comments
 (0)