'AccessTokenCredentials' object has no attribute 'sign_blob'
VJalili opened this issue · 10 comments
Use the following to reproduce:
from cloudbridge.factory import CloudProviderFactory, ProviderList
config = {"gcp_credentials_obj": credentials, "gcp_service_creds_dict": {"project_id": "..."}}
provider = CloudProviderFactory().create_provider(ProviderList.GCP, config)
bucket = provider.storage.buckets.get("...")
key = bucket.objects.get("...")
signed_url = key.generate_url(expires_in=3600)
where the credentials
object is of type oauth2client.client.AccessTokenCredentials
. Calling the generate_url
method raises an exception with the following traceback:
Traceback (most recent call last):
File "gcp.py", line 42, in <module>
signed_url = key.generate_url(expires_in=3600)
File "../cloudbridge/providers/gcp/resources.py", line 1985, in generate_url
(expiration, self._obj['bucket'], self.name))
File "../cloudbridge/providers/gcp/provider.py", line 314, in sign_blob
return self._credentials.sign_blob(string_to_sign)[1]
AttributeError: 'AccessTokenCredentials' object has no attribute 'sign_blob'
@nuwang what is the expected type of self._credentials
here? AssertionCredentials
?!
If so, it seems both AssertionCredentials
and AccessTokenCredentials
inherit from OAuth2Credentials
:
Object -> Credentials -> OAuth2Credentials -> GoogleCredentials -> AssertionCredentials
Object -> Credentials -> OAuth2Credentials -> AccessTokenCredentials
Type used by CloudBridge currently: oauth2client.service_account.ServiceAccountCredentials
ServiceAccountCredentials
type inherits fromAssertionCredentials
;- signing access to X using this method requires credentials files of a service account that has access to X, but we do not such a credentials file with the authorization flow we're using. Hence, with the blob signed using the linked method, you get
Access denied
error. In other words, that approach requires RSA private key of a service account that has access to X, we the authorization flow we're using, we do not have such a RSA private key.
What do you think of this?
https://google-auth.readthedocs.io/en/latest/_modules/google/auth/iam.html
As the docs say in that file say: "This is useful when you need to sign bytes but do not have access to the credential's private key file."
It calls a rest api endpoint to sign the string:
https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/signBlob
Would this be an option?
Do you have an example of how this can be used?
Additionally, looking into related libraries, it seems if we can initialize a signer using access token, then the rest should be straightforward. The question is how to initialize a signer using access token? I found the following method but its not clear to me how it works:
https://gist.github.com/frankyn/1a537900c0689903f157740a0a9e36aa#file-v4_signed_urls-rb-L60
This example: googleapis/google-auth-library-python#50 (comment)
How did you make that work? I don't see how access token is passed there, are you using an environment variable?
Also, I suspect this is using default credentials types (similar to the default method of initializing GCP backend of cloudbridge) and not access token or AccessTokenCredentials
.
oauth2client was recently deprecated in favor of this [google-auth] library
REF
Both ServiceAccountCredentials
(that CloudBridge uses) and AccessTokenCredentials
(that CloudAuthz generates) are part of this now deprecated library. I guess with that we need to revisit both cloudauthz and cloudbridge and update them to use google-auth
.
Switching to the new library, we can use google.oauth2.service_account.Credentials
type instead of oauth2client.client.AccessTokenCredentials
, which implements a signer
method that returns a singer that can be used for signing blobs (how to sign blobs using a signer is another question, but it is one step in the right direction).
This is sorted I guess, so closing.