google-cloud-java: Storage.signUrl() fails with default credentials in java8 standard runtime

Invocation:

// initialization
storage = StorageOptions.getDefaultInstance().getService();

// later
storage.signUrl(info, 5L, TimeUnit.MINUTES,
                Storage.SignUrlOption.httpMethod(HttpMethod.valueOf(method)),
                Storage.SignUrlOption.withContentType()
        );

Stacktrace:

Caused by: java.lang.IllegalStateException: Signing key was not provided and could not be derived
	at com.google.common.base.Preconditions.checkState(Preconditions.java:444)
	at com.google.cloud.storage.StorageImpl.signUrl(StorageImpl.java:508)

I tracked the problem down to the com.google.auth.oauth2.GoogleCredentials.getDefaultCredentialsUnsynchronized()(https://github.com/google/google-auth-library-java/blob/51a5445b33d10f252cadfdcca82dd9e68512e483/oauth2_http/java/com/google/auth/oauth2/DefaultCredentialsProvider.java#L182) where it skips over tryGetAppEngineCredential() to return an instance of com.google.auth.oauth2.AppengineCredentials which is one of the implementations of ServiceAccountSigner required by the signUrl call with default credentials.

This may also affect other services assuming an instance of com.google.auth.oauth2.AppengineCredentials.

Is there any specific reason why to check for java7 only?

Background: We moved to the java8 runtime on GAE and upgraded our api clients to the google-cloud-java api clients version 1.10.0.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 2
  • Comments: 24 (12 by maintainers)

Most upvoted comments

I had the same problem (using 1.35.0): Caused by: java.lang.IllegalStateException: Signing key was not provided and could not be derived

Using AppEngine standard, I solved like this:

        static final AppIdentityService identityService = AppIdentityServiceFactory.getAppIdentityService();

        SignUrlOption signWith = SignUrlOption.signWith(new ServiceAccountSigner() {
            @Override
            public byte[] sign(byte[] toSign) {
                return identityService.signForApp(toSign).getSignature();
            }

            @Override
            public String getAccount() {
                return identityService.getServiceAccountName();
            }
        });

I needed to grant iam.serviceAccounts.signBlob in order for the default service account to sign URLs while running in App Engine, but running locally with the same credentials didn’t require this—is this a bug?

google.auth.version has been bumped. Please update the library to the latest version (1.38.0) and see if the problem is resolved.

Same issue is present in flexible runtime too?