-
Notifications
You must be signed in to change notification settings - Fork 431
Clean up Service Account support #211
Comments
Hi, would you like to me to do the change and make a pull request for this? Sandeep |
No I or some other maintainer can handle it. I just wanted to give a source for the issue. Thanks though! |
I played around a bit and it seems like P12->JSON is possible but JSON->P12 is not. The reason is that a P12 key is made up of a PEM certificate and a PEM key, which can be seen via: from OpenSSL import crypto
with open('keyfile.p12', 'rb') as fh:
p12 = crypto.load_pkcs12(fh.read(), 'notasecret')
print crypto.dump_privatekey(crypto.FILETYPE_PEM, p12.get_privatekey())
print crypto.dump_certificate(crypto.FILETYPE_PEM, p12.get_certificate()) On the other hand, the JSON key file has a This manifests in the first section of the JWT sent (the header). For the P12 {
"alg": "RS256",
"typ": "JWT"
} vs. for a JSON key (with a {
"alg": "RS256",
"kid": "DEADBEEF",
"typ": "JWT"
} This may not matter if we never use the certificate from the P12 key. |
As it turns out, JSON->P12 can be done as well (at least for getting an access token). It's as easy as
p12_obj = crypto.PKCS12() # 1
p12_obj.set_privatekey(crypto.load_privatekey( # 2
crypto.FILETYPE_PEM, private_key))
with open(JSON_AS_P12, 'wb') as fh: # 3
fh.write(p12_obj.export(passphrase=PASSPHRASE)) See my gist at the latest revision to see all cases covered. |
Some notes on differences and similarities between Similarities:
Differences
Noteworthy
ISTM the "best" path forward is to do one of the following two things
|
Changed diff --git a/oauth2client/service_account.py b/oauth2client/service_account.py
index d1d1d89..8120c6c 100644
--- a/oauth2client/service_account.py
+++ b/oauth2client/service_account.py
@@ -62,7 +62,6 @@ class _ServiceAccountCredentials(AssertionCredentials):
header = {
'alg': 'RS256',
'typ': 'JWT',
- 'kid': self._private_key_id
}
now = int(time.time()) and tested that minting a token worked, and not sending a |
I'm actually using What is missing is a simple public method for creating service account credentials using only five pieces of data: the client ID, client email, private key ID, private key, and authentication scopes. If you can make such a method then this would help greatly, and this information can often be loaded not just from raw JSON files but via via internal custom config-type objects ( The complexity of loading authentication information from a file is obvious from the code for |
@sr-murthy Thanks for letting us know. The plan right now is to make one class with two easy to use factory methods. For example: p12_creds = ServiceAccountCredentials.from_p12(client_email, p12_key_path)
json_creds = ServiceAccountCredentials.from_json(json_key_path) Also, please don't depend on private / protected methods, functions, or classes as they may be deprecated / removed in future releases. |
Some context. The "private_key_id" can in theory apply to p12 keys also, but you would have to provide it as a separate input, e.g. as an optional 3rd parameter to "from_p12" because it is not in that file. As you discovered, nothing breaks if you remove it, but we were advised to put this in by security experts. Apparently it can help performance and diagnostics on the server side, as it can identify which of N keys you are talking about and can be used to do things like revoke the key in the UI. The pattern suggested here of making _ServiceAccountCredentials public and adding P12 support sounds good here. I would suggest the following factories: from_p12file(client_email, p12_key_path); The from_json would be a dictionary in memory. One other change that I would add here is that we should remove all reference to the "service account id". This is the "client id" of the service account and this is being removed from the console UI and there is a desire to eventually remove this from the json file as well. |
Thanks for chiming in! That's fine with me. Re |
OK. We should find another name like from_dictionary for this, but the function is needed. Code that reads a file that could be either user or a service account needs to forward the dictionary it parses on to this method. |
Totally agree 👍 |
@nathanielmanistaatgoogle I'm close to "done" here. Will send a non-merge-able PR and ping you on it by EOD. Then we can discuss how to break it up for review. |
See the discussion in #207. Though not directly related, it revealed a few things.
service_account._ServiceAccountCredentials
class that does essentially the same thing thatclient.SignedJwtAssertionCredentials
doesThe text was updated successfully, but these errors were encountered: