diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java index 0c92a1f50594..b6f668dada82 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Blob.java @@ -22,6 +22,7 @@ import com.google.api.services.storage.model.StorageObject; import com.google.common.base.Function; +import com.google.gcloud.AuthCredentials; import com.google.gcloud.ReadChannel; import com.google.gcloud.WriteChannel; import com.google.gcloud.storage.Storage.BlobTargetOption; @@ -453,16 +454,48 @@ public WriteChannel writer(BlobWriteOption... options) { } /** - * Generates a signed URL for this blob. If you want to allow access to for a fixed amount of time - * for this blob, you can use this method to generate a URL that is only valid within a certain - * time period. This is particularly useful if you don't want publicly accessible blobs, but don't - * want to require users to explicitly log in. + * Generates a signed URL for this blob. If you want to allow access for a fixed amount of time to + * this blob, you can use this method to generate a URL that is only valid within a certain time + * period. This is particularly useful if you don't want publicly accessible blobs, but also don't + * want to require users to explicitly log in. Signing a URL requires a service account and its + * associated private key. If a {@link AuthCredentials.ServiceAccountAuthCredentials} was passed + * to {@link StorageOptions.Builder#authCredentials(AuthCredentials)} or the default credentials + * are being used and the environment variable {@code GOOGLE_APPLICATION_CREDENTIALS} is set, then + * {@code signUrl} will use that service account and associated key to sign the URL. If the + * credentials passed to {@link StorageOptions} do not expose a private key (this is the case for + * App Engine credentials, Compute Engine credentials and Google Cloud SDK credentials) then + * {@code signUrl} will throw an {@link IllegalArgumentException} unless a service account with + * associated key is passed using the {@code SignUrlOption.serviceAccount()} option. The service + * account and private key passed with {@code SignUrlOption.serviceAccount()} have priority over + * any credentials set with {@link StorageOptions.Builder#authCredentials(AuthCredentials)}. + * + *

Example usage of creating a signed URL that is valid for 2 weeks, using the default + * credentials for signing the URL: + *

 {@code
+   * blob.signUrl(14, TimeUnit.DAYS);
+   * }
+ * + *

Example usage of creating a signed URL passing the {@code SignUrlOption.serviceAccount()} + * option, that will be used for signing the URL: + *

 {@code
+   * blob.signUrl(14, TimeUnit.DAYS, SignUrlOption.serviceAccount(
+   *     AuthCredentials.createForJson(new FileInputStream("/path/to/key.json"))));
+   * }
* * @param duration time until the signed URL expires, expressed in {@code unit}. The finer * granularity supported is 1 second, finer granularities will be truncated * @param unit time unit of the {@code duration} parameter * @param options optional URL signing options * @return a signed URL for this bucket and the specified options + * @throws IllegalArgumentException if + * {@link SignUrlOption#serviceAccount(AuthCredentials.ServiceAccountAuthCredentials)} was not + * used and no service account was provided to {@link StorageOptions} + * @throws IllegalArgumentException if the key associated to the provided service account is + * invalid + * @throws IllegalArgumentException if {@link SignUrlOption#withMd5()} option is used and + * {@link #md5()} is {@code null} + * @throws IllegalArgumentException if {@link SignUrlOption#withContentType()} option is used and + * {@link #contentType()} is {@code null} * @see Signed-URLs */ public URL signUrl(long duration, TimeUnit unit, SignUrlOption... options) { diff --git a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java index c098c7ddc5d3..c30111e50835 100644 --- a/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java +++ b/gcloud-java-storage/src/main/java/com/google/gcloud/storage/Storage.java @@ -24,6 +24,7 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.google.gcloud.AuthCredentials; import com.google.gcloud.AuthCredentials.ServiceAccountAuthCredentials; import com.google.gcloud.Page; import com.google.gcloud.ReadChannel; @@ -1476,23 +1477,48 @@ private static void checkContentType(BlobInfo blobInfo) throws IllegalArgumentEx WriteChannel writer(BlobInfo blobInfo, BlobWriteOption... options); /** - * Generates a signed URL for a blob. - * If you have a blob that you want to allow access to for a fixed - * amount of time, you can use this method to generate a URL that - * is only valid within a certain time period. - * This is particularly useful if you don't want publicly - * accessible blobs, but don't want to require users to explicitly log in. + * Generates a signed URL for a blob. If you have a blob that you want to allow access to for a + * fixed amount of time, you can use this method to generate a URL that is only valid within a + * certain time period. This is particularly useful if you don't want publicly accessible blobs, + * but also don't want to require users to explicitly log in. Signing a URL requires a service + * account and its associated private key. If a {@link ServiceAccountAuthCredentials} was passed + * to {@link StorageOptions.Builder#authCredentials(AuthCredentials)} or the default credentials + * are being used and the environment variable {@code GOOGLE_APPLICATION_CREDENTIALS} is set, then + * {@code signUrl} will use that service account and associated key to sign the URL. If the + * credentials passed to {@link StorageOptions} do not expose a private key (this is the case for + * App Engine credentials, Compute Engine credentials and Google Cloud SDK credentials) then + * {@code signUrl} will throw an {@link IllegalArgumentException} unless a service account with + * associated key is passed using the {@code SignUrlOption.serviceAccount()} option. The service + * account and private key passed with {@code SignUrlOption.serviceAccount()} have priority over + * any credentials set with {@link StorageOptions.Builder#authCredentials(AuthCredentials)}. * - *

Example usage of creating a signed URL that is valid for 2 weeks: + *

Example usage of creating a signed URL that is valid for 2 weeks, using the default + * credentials for signing the URL: *

 {@code
    * service.signUrl(BlobInfo.builder("bucket", "name").build(), 14, TimeUnit.DAYS);
    * }
* + *

Example usage of creating a signed URL passing the {@code SignUrlOption.serviceAccount()} + * option, that will be used for signing the URL: + *

 {@code
+   * service.signUrl(BlobInfo.builder("bucket", "name").build(), 14, TimeUnit.DAYS,
+   *     SignUrlOption.serviceAccount(
+   *         AuthCredentials.createForJson(new FileInputStream("/path/to/key.json"))));
+   * }
+ * * @param blobInfo the blob associated with the signed URL * @param duration time until the signed URL expires, expressed in {@code unit}. The finest * granularity supported is 1 second, finer granularities will be truncated * @param unit time unit of the {@code duration} parameter * @param options optional URL signing options + * @throws IllegalArgumentException if {@code SignUrlOption.serviceAccount()} was not used and no + * service account was provided to {@link StorageOptions} + * @throws IllegalArgumentException if the key associated to the provided service account is + * invalid + * @throws IllegalArgumentException if {@code SignUrlOption.withMd5()} option is used and + * {@code blobInfo.md5()} is {@code null} + * @throws IllegalArgumentException if {@code SignUrlOption.withContentType()} option is used and + * {@code blobInfo.contentType()} is {@code null} * @see Signed-URLs */ URL signUrl(BlobInfo blobInfo, long duration, TimeUnit unit, SignUrlOption... options);