[GH-ISSUE #1073] Cannot use signed url with java #162

Closed
opened 2026-03-03 12:08:50 +03:00 by kerem · 5 comments
Owner

Originally created by @marcelocamanho on GitHub (Feb 14, 2023).
Original GitHub issue: https://github.com/fsouza/fake-gcs-server/issues/1073

Was anyone able to use them?
I am using a simple code to init the storage service and to access it, but it fails.

StorageOptions.Builder storageOptions = StorageOptions.newBuilder().setProjectId(projectId);
storageOptions.setHost("http://localhost:1234");
BlobInfo blobInfo = BlobInfo.newBuilder(BlobId.of(bucketName, objectName)).build();
URL url = storage.signUrl(blobInfo, 10, TimeUnit.MINUTES, Storage.SignUrlOption.withV4Signature());

This causes the error:

java.lang.IllegalStateException: Signing key was not provided and could not be derived
	at com.google.common.base.Preconditions.checkState(Preconditions.java:444) ~[guava-20.0.jar:na]
	at com.google.cloud.storage.StorageImpl.signUrl(StorageImpl.java:627) ~[google-cloud-storage-2.8.1.jar:2.8.1]

Was anyone able to work around this please?

Thanks

Originally created by @marcelocamanho on GitHub (Feb 14, 2023). Original GitHub issue: https://github.com/fsouza/fake-gcs-server/issues/1073 Was anyone able to use them? I am using a simple code to init the storage service and to access it, but it fails. ``` StorageOptions.Builder storageOptions = StorageOptions.newBuilder().setProjectId(projectId); storageOptions.setHost("http://localhost:1234"); BlobInfo blobInfo = BlobInfo.newBuilder(BlobId.of(bucketName, objectName)).build(); URL url = storage.signUrl(blobInfo, 10, TimeUnit.MINUTES, Storage.SignUrlOption.withV4Signature()); ``` This causes the error: ``` java.lang.IllegalStateException: Signing key was not provided and could not be derived at com.google.common.base.Preconditions.checkState(Preconditions.java:444) ~[guava-20.0.jar:na] at com.google.cloud.storage.StorageImpl.signUrl(StorageImpl.java:627) ~[google-cloud-storage-2.8.1.jar:2.8.1] ``` Was anyone able to work around this please? Thanks
kerem 2026-03-03 12:08:50 +03:00
  • closed this issue
  • added the
    question
    label
Author
Owner

@fsouza commented on GitHub (May 2, 2023):

Hey @marcelocamanho, sorry for such a delayed response, I completely missed this issue. Signing URLs doesn't really involve the server, so you need a valid key to sign even if you're using a fake server. What I've seen other folks do in the past is generating some sort of X.509 certificate or even generating a real one from Google, invalidating it and then using in tests/CI.

<!-- gh-comment-id:1531676516 --> @fsouza commented on GitHub (May 2, 2023): Hey @marcelocamanho, sorry for such a delayed response, I completely missed this issue. Signing URLs doesn't really involve the server, so you need a valid key to sign even if you're using a fake server. What I've seen other folks do in the past is generating some sort of X.509 certificate or even generating a real one from Google, invalidating it and then using in tests/CI.
Author
Owner

@SamueLacmene commented on GitHub (Dec 21, 2023):

@marcelocamanho Did you find a solution to your Problem? I'm facing the same issue. If yes can you please share you solution ?! :-)

<!-- gh-comment-id:1865998403 --> @SamueLacmene commented on GitHub (Dec 21, 2023): @marcelocamanho Did you find a solution to your Problem? I'm facing the same issue. If yes can you please share you solution ?! :-)
Author
Owner

@SamueLacmene commented on GitHub (Dec 21, 2023):

I managed to mock the credential, so that the method storage.signUrl was able to work without having to use a service-account-key.json. Here is the solution:

@Configuration
class GoogleCloudStorageConfiguration {

  @Value("\${gcs.port}")
  private lateinit var gcsContainerPort: String

  @Bean
  @Primary
  fun storage(): Storage {
    val serviceAccountCredentials = mock<ServiceAccountCredentials> {
      on { account } doReturn "Account"
      on { sign(any()) } doReturn byteArrayOf(123456.toByte())
    }

    return StorageOptions.getUnauthenticatedInstance().toBuilder()
      .setHost("http://localhost:$gcsContainerPort")
      .setCredentials(serviceAccountCredentials)
      .build()
      .service
  }
}

I'm using Sprint + kotlin + mockito

import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
<!-- gh-comment-id:1866654869 --> @SamueLacmene commented on GitHub (Dec 21, 2023): I managed to mock the credential, so that the method `storage.signUrl` was able to work without having to use a `service-account-key.json`. Here is the solution: ``` @Configuration class GoogleCloudStorageConfiguration { @Value("\${gcs.port}") private lateinit var gcsContainerPort: String @Bean @Primary fun storage(): Storage { val serviceAccountCredentials = mock<ServiceAccountCredentials> { on { account } doReturn "Account" on { sign(any()) } doReturn byteArrayOf(123456.toByte()) } return StorageOptions.getUnauthenticatedInstance().toBuilder() .setHost("http://localhost:$gcsContainerPort") .setCredentials(serviceAccountCredentials) .build() .service } } ``` I'm using Sprint + kotlin + mockito ``` import org.mockito.kotlin.any import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock ```
Author
Owner

@Burtan commented on GitHub (Dec 27, 2023):

While the fake signing is working for me. The generated url does not use the fake gcs url, but https://storage.googleapis.com/.
I see, it is working as intended.
https://github.com/fsouza/fake-gcs-server#using-with-signed-urls

<!-- gh-comment-id:1870119197 --> @Burtan commented on GitHub (Dec 27, 2023): While the fake signing is working for me. The generated url does not use the fake gcs url, but https://storage.googleapis.com/. I see, it is working as intended. https://github.com/fsouza/fake-gcs-server#using-with-signed-urls
Author
Owner

@tlusk commented on GitHub (Jun 26, 2025):

Here's a way you can create a new ServiceAccountCredentials object without needing to mock it like the above solution:

val storage = StorageOptions.newBuilder()
  .setCredentials(
      ServiceAccountCredentials.newBuilder().apply {
          clientEmail = "TestAccount"
          privateKey = KeyPairGenerator.getInstance("RSA").generateKeyPair().private
      }.build(),
  )
  .build().service
<!-- gh-comment-id:3010259966 --> @tlusk commented on GitHub (Jun 26, 2025): Here's a way you can create a new `ServiceAccountCredentials` object without needing to mock it like the above solution: ```kotlin val storage = StorageOptions.newBuilder() .setCredentials( ServiceAccountCredentials.newBuilder().apply { clientEmail = "TestAccount" privateKey = KeyPairGenerator.getInstance("RSA").generateKeyPair().private }.build(), ) .build().service ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/fake-gcs-server#162
No description provided.