|
16 | 16 |
|
17 | 17 | package com.google.gcloud.storage; |
18 | 18 |
|
| 19 | +import static com.google.common.base.MoreObjects.firstNonNull; |
19 | 20 | import static com.google.common.base.Preconditions.checkArgument; |
20 | 21 | import static com.google.common.base.Preconditions.checkNotNull; |
21 | 22 |
|
22 | 23 | import com.google.common.collect.ImmutableList; |
| 24 | +import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials; |
23 | 25 | import com.google.gcloud.Service; |
24 | 26 | import com.google.gcloud.spi.StorageRpc; |
25 | 27 |
|
| 28 | +import org.joda.time.DateTime; |
| 29 | + |
26 | 30 | import java.io.Serializable; |
| 31 | +import java.net.URL; |
27 | 32 | import java.util.Arrays; |
28 | 33 | import java.util.Collections; |
29 | 34 | import java.util.LinkedHashSet; |
@@ -407,6 +412,139 @@ public static Builder builder() { |
407 | 412 | } |
408 | 413 | } |
409 | 414 |
|
| 415 | + /** |
| 416 | + * A request for signing a URL. |
| 417 | + */ |
| 418 | + class SignUrlRequest implements Serializable { |
| 419 | + |
| 420 | + private final Blob blob; |
| 421 | + private final HttpMethod httpMethod; |
| 422 | + private final Long expiration; |
| 423 | + private final boolean includeContentType; |
| 424 | + private final boolean includeMd5; |
| 425 | + private final String headers; |
| 426 | + private final ServiceAccountAuthCredentials authCredentials; |
| 427 | + |
| 428 | + public static class Builder { |
| 429 | + |
| 430 | + private Blob blob; |
| 431 | + private HttpMethod httpMethod; |
| 432 | + private long expiration; |
| 433 | + private boolean includeContentType; |
| 434 | + private boolean includeMd5; |
| 435 | + private String headers; |
| 436 | + private ServiceAccountAuthCredentials authCredentials; |
| 437 | + |
| 438 | + private Builder() {} |
| 439 | + |
| 440 | + public Builder blob(Blob blob) { |
| 441 | + this.blob = blob; |
| 442 | + return this; |
| 443 | + } |
| 444 | + |
| 445 | + /** |
| 446 | + * The HTTP method to be used with the signed URL. |
| 447 | + */ |
| 448 | + public Builder httpMethod(HttpMethod httpMethod) { |
| 449 | + this.httpMethod = httpMethod; |
| 450 | + return this; |
| 451 | + } |
| 452 | + |
| 453 | + /** |
| 454 | + * Sets expiration time for the URL. |
| 455 | + * Defaults to one day. |
| 456 | + */ |
| 457 | + public Builder expiration(long expiration) { |
| 458 | + this.expiration = expiration; |
| 459 | + return this; |
| 460 | + } |
| 461 | + |
| 462 | + /** |
| 463 | + * Indicate if signature should include the blob's content-type. |
| 464 | + * If {@code true} users of the signed URL should include |
| 465 | + * the same content-type with their request. |
| 466 | + */ |
| 467 | + public Builder includeContentType(boolean includeContentType) { |
| 468 | + this.includeContentType = includeContentType; |
| 469 | + return this; |
| 470 | + } |
| 471 | + |
| 472 | + /** |
| 473 | + * Indicate if signature should include the blob's md5. |
| 474 | + * If {@code true} users of the signed URL should include it with their requests. |
| 475 | + */ |
| 476 | + public Builder includeMd5(boolean includeMd5) { |
| 477 | + this.includeMd5 = includeMd5; |
| 478 | + return this; |
| 479 | + } |
| 480 | + |
| 481 | + /** |
| 482 | + * If headers are provided, the server will check to make sure that the client |
| 483 | + * provides matching values. |
| 484 | + * For information about how to create canonical headers for signing, |
| 485 | + * see <a href="https://cloud.google.com/storage/docs/access-control#About-CanonicalExtensionHeaders">About Canonical Extension Headers</a>. |
| 486 | + */ |
| 487 | + public Builder canonicalizedExtensionHeaders(String headers) { |
| 488 | + this.headers = headers; |
| 489 | + return this; |
| 490 | + } |
| 491 | + |
| 492 | + /** |
| 493 | + * The service account credentials for signing the URL. |
| 494 | + */ |
| 495 | + public Builder serviceAccountAuthCredentials(ServiceAccountAuthCredentials authCredentials) { |
| 496 | + this.authCredentials = authCredentials; |
| 497 | + return this; |
| 498 | + } |
| 499 | + |
| 500 | + public SignUrlRequest build() { |
| 501 | + return new SignUrlRequest(this); |
| 502 | + } |
| 503 | + } |
| 504 | + |
| 505 | + private SignUrlRequest(Builder builder) { |
| 506 | + blob = checkNotNull(builder.blob); |
| 507 | + httpMethod = builder.httpMethod; |
| 508 | + expiration = firstNonNull(builder.expiration, new DateTime().plusDays(1).getMillis()); |
| 509 | + includeContentType = builder.includeContentType; // verify blob has content-type |
| 510 | + includeMd5 = builder.includeMd5; // verify blob has md5 |
| 511 | + authCredentials = builder.authCredentials; // default if null |
| 512 | + headers = builder.headers; |
| 513 | + } |
| 514 | + |
| 515 | + public Blob blob() { |
| 516 | + return blob; |
| 517 | + } |
| 518 | + |
| 519 | + public HttpMethod httpMethod() { |
| 520 | + return httpMethod; |
| 521 | + } |
| 522 | + |
| 523 | + public String canonicalizedExtensionHeaders() { |
| 524 | + return headers; |
| 525 | + } |
| 526 | + |
| 527 | + public long expiration() { |
| 528 | + return expiration; |
| 529 | + } |
| 530 | + |
| 531 | + public ServiceAccountAuthCredentials authCredentials() { |
| 532 | + return authCredentials; |
| 533 | + } |
| 534 | + |
| 535 | + public boolean includeContentType() { |
| 536 | + return includeContentType; |
| 537 | + } |
| 538 | + |
| 539 | + public boolean includeMd5() { |
| 540 | + return includeMd5; |
| 541 | + } |
| 542 | + |
| 543 | + public static Builder builder() { |
| 544 | + return new Builder(); |
| 545 | + } |
| 546 | + } |
| 547 | + |
410 | 548 | /** |
411 | 549 | * Create a new bucket. |
412 | 550 | * |
@@ -528,4 +666,14 @@ public static Builder builder() { |
528 | 666 | * @throws StorageServiceException upon failure |
529 | 667 | */ |
530 | 668 | BlobWriteChannel writer(Blob blob, BlobTargetOption... options); |
| 669 | + |
| 670 | + /** |
| 671 | + * Generates a signed URL for a blob. |
| 672 | + * If you have a blob that you want to allow access to for a set |
| 673 | + * amount of time, you can use this method to generate a URL that |
| 674 | + * is only valid within a certain time period. |
| 675 | + * This is particularly useful if you don't want publicly |
| 676 | + * accessible blobs, but don't want to require users to explicitly log in. |
| 677 | + */ |
| 678 | + URL signUrl(SignUrlRequest request); |
531 | 679 | } |
0 commit comments