-
Notifications
You must be signed in to change notification settings - Fork 431
Helpful error message in P12 factory in absence of pyOpenSSL. #424
Conversation
Looks good; merge when you please. |
Helpful error message in P12 factory in absence of pyOpenSSL.
@@ -240,6 +240,8 @@ def _from_p12_keyfile_contents(cls, service_account_email, | |||
""" | |||
if private_key_password is None: | |||
private_key_password = _PASSWORD_DEFAULT | |||
if crypt.Signer is not crypt.OpenSSLSigner: |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
Hi, this seems to have introduced a bug. You can no longer use any other signer as the OpenSSL one. This seems strange, is that intended behavior? Cheers, |
The
|
I use Django on Heroku. On Heroku you can't store files except in your repository. Adding a private key to the repository is not the best idea I guess ;) I wrote that little bit of code that worked for me until this change: def build_googleapiclient(service_email=None, private_key=None,
user_email=None):
service_email = service_email or settings.GOOGLE_DRIVE_STORAGE_SERVICE_EMAIL
key = private_key or settings.GOOGLE_DRIVE_STORAGE_KEY
credentials = ServiceAccountCredentials._from_p12_keyfile_contents(
service_email,
key,
scopes="https://www.googleapis.com/auth/drive",
)
credentials = credentials.create_delegated(user_email)
http = httplib2.Http()
http = credentials.authorize(http)
return build('drive', 'v2', http=http) I know it's not nice to use a private API and than complain, but hey ;) Since my private key start with |
I'd first and foremost just recommend getting a JSON key file from Google, since it's unclear where you got the PKCS#1 key from. (A JSON keyfile is a JSON-ified dict, with a field that holds a PKCS#8 key in PEM format.) If you want to proceed "as-is" by just constructing any old signer: signer = crypt.Signer.from_string(settings.GOOGLE_DRIVE_STORAGE_KEY)
creds = ServiceAccountCredentials(
settings.GOOGLE_DRIVE_STORAGE_SERVICE_EMAIL, signer,
scopes='https://www.googleapis.com/auth/drive',
sub=user_email)
# OPTIONAL HACKY SNIPPET FOR SERIALIZATION
creds._private_key_pkcs8_pem = settings.GOOGLE_DRIVE_STORAGE_KEY
# DEFINITELY A LIE SINCE YOUR STORAGE KEY IS PKCS#1, NOT PKCS#8 Can you give an idea / snippet of what you were doing before (with |
@dhermes: sure, reversion says we used this one :) def build_googleapiclient(service_email=None, private_key=None,
user_email=None):
service_email = service_email or settings.GOOGLE_DRIVE_STORAGE_SERVICE_EMAIL
key = private_key or settings.GOOGLE_DRIVE_STORAGE_KEY
kwargs = {}
if user_email:
kwargs['sub'] = user_email
credentials = SignedJwtAssertionCredentials(
service_email,
key,
scope="https://www.googleapis.com/auth/drive",
**kwargs
)
http = httplib2.Http()
http = credentials.authorize(http)
return build('drive', 'v2', http=http) Is the JSON key file available now for server2server communication? We needed a user that can modify out Drive regardless of the current user. |
The key you have is fine. Yes a JSON keyfile is a keyfile for a Google service account. The snippets I mentioned above will work for you (I'm 99.9% sure your PKCS#1 key is just converted from an original P12 key downloaded from Google). |
@dhermes thanks! I just saw that you can now create json files for service accounts. I just created new creds for the account in json: def build_googleapiclient(user_email=None):
key = json.loads(settings.GOOGLE_DRIVE_STORAGE_KEYP)
credentials = ServiceAccountCredentials._from_parsed_json_keyfile(
key,
scopes="https://www.googleapis.com/auth/drive",
)
if user_email is not None:
credentials = credentials.create_delegated(user_email)
http = httplib2.Http()
http = credentials.authorize(http)
return build('drive', 'v2', http=http) This works fine for me. Forget the rest ;) |
Good deal! I strongly encourage you just use ServiceAccountCredentials.from_json_keyfile_name(
settings.GOOGLE_DRIVE_STORAGE_KEYP,
scopes='https://www.googleapis.com/auth/drive') instead of using a non-public interface. |
@dhermes that is a nice Idea, but again, I can't store files on Heroku that are not in the git repository. |
Sorry I misread the Still, you don't need the non-public method. Use http://oauth2client.readthedocs.org/en/latest/source/oauth2client.service_account.html#oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_dict |
Good point, thx! |
Fixes #417.
@nathanielmanistaatgoogle I'm not sure why this didn't make it in the re-write. I definitely had tests for this and an
if crypt.Signer
check.Sorry @ddoskind that I absent-mindedly let it slip in #398 (it was in #392 but I dropped the
_get_signer
helper since only the factories need to make a signer now rather than the constructor back then)