Skip to content

Commit 9955998

Browse files
committed
complete work on signURL
1 parent ebb069c commit 9955998

File tree

7 files changed

+96
-12
lines changed

7 files changed

+96
-12
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-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
@@ -81,8 +81,8 @@ public DefaultStorageRpc(StorageServiceOptions options) {
8181
HttpTransport transport = options.httpTransportFactory().create();
8282
HttpRequestInitializer initializer = options.httpRequestInitializer();
8383
this.options = options;
84-
// todo: validate what is returned by getRootURL and use that for host default (and use host())
8584
storage = new Storage.Builder(transport, new JacksonFactory(), initializer)
85+
.setRootUrl(options.host())
8686
.setApplicationName("gcloud-java")
8787
.build();
8888
}

gcloud-java-storage/src/main/java/com/google/gcloud/storage/StorageServiceImpl.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import static com.google.gcloud.spi.StorageRpc.Option.IF_SOURCE_METAGENERATION_MATCH;
3030
import static com.google.gcloud.spi.StorageRpc.Option.IF_SOURCE_METAGENERATION_NOT_MATCH;
3131
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
32+
import static java.nio.charset.StandardCharsets.UTF_8;
3233

3334
import com.google.api.services.storage.model.StorageObject;
3435
import com.google.common.base.Function;
@@ -51,6 +52,7 @@
5152
import java.io.UnsupportedEncodingException;
5253
import java.net.MalformedURLException;
5354
import java.net.URL;
55+
import java.net.URLEncoder;
5456
import java.security.InvalidKeyException;
5557
import java.security.NoSuchAlgorithmException;
5658
import java.security.Signature;
@@ -467,7 +469,7 @@ public URL signUrl(Blob blob, long expiration, SignUrlOption... options) {
467469
stBuilder.append(blob.contentType());
468470
}
469471
stBuilder.append('\n');
470-
stBuilder.append(expiration).append('\n').append('\n');
472+
stBuilder.append(expiration).append('\n');
471473
StringBuilder path = new StringBuilder();
472474
if (!blob.bucket().startsWith("/")) {
473475
path.append('/');
@@ -484,9 +486,9 @@ public URL signUrl(Blob blob, long expiration, SignUrlOption... options) {
484486
try {
485487
Signature signer = Signature.getInstance("SHA256withRSA");
486488
signer.initSign(cred.privateKey());
487-
signer.update(stBuilder.toString().getBytes("UTF-8"));
488-
String signature = BaseEncoding.base64Url().encode(signer.sign());
489-
// todo - use options().host() - after default is correct and value is past to RPC
489+
signer.update(stBuilder.toString().getBytes(UTF_8));
490+
String signature =
491+
URLEncoder.encode(BaseEncoding.base64().encode(signer.sign()), UTF_8.name());
490492
stBuilder = new StringBuilder("https://storage.googleapis.com").append(path);
491493
stBuilder.append("?GoogleAccessId=").append(cred.account());
492494
stBuilder.append("&Expires=").append(expiration);

gcloud-java-storage/src/test/java/com/google/gcloud/storage/CorsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void testOrigin() {
3838
public void corsTest() {
3939
List<Origin> origins = ImmutableList.of(Origin.any(), Origin.of("o"));
4040
List<String> headers = ImmutableList.of("h1", "h2");
41-
List<HttpMethod> methods = ImmutableList.of(HttpMethod.ANY);
41+
List<HttpMethod> methods = ImmutableList.of(HttpMethod.GET);
4242
Cors cors = Cors.builder()
4343
.maxAgeSeconds(100)
4444
.origins(origins)

pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,19 @@
8585
</pluginRepository>
8686
</pluginRepositories>
8787
<build>
88+
<pluginManagement>
89+
<plugins>
90+
<plugin>
91+
<groupId>org.codehaus.mojo</groupId>
92+
<artifactId>exec-maven-plugin</artifactId>
93+
<version>1.3.2</version>
94+
<configuration>
95+
<skip>true</skip>
96+
<executable>java</executable>
97+
</configuration>
98+
</plugin>
99+
</plugins>
100+
</pluginManagement>
88101
<plugins>
89102
<plugin>
90103
<groupId>org.codehaus.mojo</groupId>

0 commit comments

Comments
 (0)