Skip to content

Commit b557440

Browse files
thobrlaJon Wayne Parrott
authored and
Jon Wayne Parrott
committed
Support token_uri and revoke_uri in ServiceAccountCredentials (googleapis#510)
This change adds support for custom authorization token and revocation URIs in the various ServiceAccountCredentials factory methods.
1 parent f5ae963 commit b557440

File tree

2 files changed

+137
-64
lines changed

2 files changed

+137
-64
lines changed

oauth2client/service_account.py

Lines changed: 89 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ class ServiceAccountCredentials(AssertionCredentials):
8181
service account.
8282
user_agent: string, (Optional) User agent to use when sending
8383
request.
84+
token_uri: string, URI for token endpoint. For convenience defaults
85+
to Google's endpoints but any OAuth 2.0 provider can be
86+
used.
87+
revoke_uri: string, URI for revoke endpoint. For convenience defaults
88+
to Google's endpoints but any OAuth 2.0 provider can be
89+
used.
8490
kwargs: dict, Extra key-value pairs (both strings) to send in the
8591
payload body when making an assertion.
8692
"""
@@ -106,10 +112,13 @@ def __init__(self,
106112
private_key_id=None,
107113
client_id=None,
108114
user_agent=None,
115+
token_uri=GOOGLE_TOKEN_URI,
116+
revoke_uri=GOOGLE_REVOKE_URI,
109117
**kwargs):
110118

111119
super(ServiceAccountCredentials, self).__init__(
112-
None, user_agent=user_agent)
120+
None, user_agent=user_agent, token_uri=token_uri,
121+
revoke_uri=revoke_uri)
113122

114123
self._service_account_email = service_account_email
115124
self._signer = signer
@@ -145,14 +154,21 @@ def _to_json(self, strip, to_serialize=None):
145154
strip, to_serialize=to_serialize)
146155

147156
@classmethod
148-
def _from_parsed_json_keyfile(cls, keyfile_dict, scopes):
157+
def _from_parsed_json_keyfile(cls, keyfile_dict, scopes,
158+
token_uri=None, revoke_uri=None):
149159
"""Helper for factory constructors from JSON keyfile.
150160
151161
Args:
152162
keyfile_dict: dict-like object, The parsed dictionary-like object
153163
containing the contents of the JSON keyfile.
154164
scopes: List or string, Scopes to use when acquiring an
155165
access token.
166+
token_uri: string, URI for OAuth 2.0 provider token endpoint.
167+
If unset and not present in keyfile_dict, defaults
168+
to Google's endpoints.
169+
revoke_uri: string, URI for OAuth 2.0 provider revoke endpoint.
170+
If unset and not present in keyfile_dict, defaults
171+
to Google's endpoints.
156172
157173
Returns:
158174
ServiceAccountCredentials, a credentials object created from
@@ -172,22 +188,35 @@ def _from_parsed_json_keyfile(cls, keyfile_dict, scopes):
172188
private_key_pkcs8_pem = keyfile_dict['private_key']
173189
private_key_id = keyfile_dict['private_key_id']
174190
client_id = keyfile_dict['client_id']
191+
if not token_uri:
192+
token_uri = keyfile_dict.get('token_uri', GOOGLE_TOKEN_URI)
193+
if not revoke_uri:
194+
revoke_uri = keyfile_dict.get('revoke_uri', GOOGLE_REVOKE_URI)
175195

176196
signer = crypt.Signer.from_string(private_key_pkcs8_pem)
177197
credentials = cls(service_account_email, signer, scopes=scopes,
178198
private_key_id=private_key_id,
179-
client_id=client_id)
199+
client_id=client_id, token_uri=token_uri,
200+
revoke_uri=revoke_uri)
180201
credentials._private_key_pkcs8_pem = private_key_pkcs8_pem
181202
return credentials
182203

183204
@classmethod
184-
def from_json_keyfile_name(cls, filename, scopes=''):
205+
def from_json_keyfile_name(cls, filename, scopes='',
206+
token_uri=None, revoke_uri=None):
207+
185208
"""Factory constructor from JSON keyfile by name.
186209
187210
Args:
188211
filename: string, The location of the keyfile.
189212
scopes: List or string, (Optional) Scopes to use when acquiring an
190213
access token.
214+
token_uri: string, URI for OAuth 2.0 provider token endpoint.
215+
If unset and not present in the key file, defaults
216+
to Google's endpoints.
217+
revoke_uri: string, URI for OAuth 2.0 provider revoke endpoint.
218+
If unset and not present in the key file, defaults
219+
to Google's endpoints.
191220
192221
Returns:
193222
ServiceAccountCredentials, a credentials object created from
@@ -200,17 +229,26 @@ def from_json_keyfile_name(cls, filename, scopes=''):
200229
"""
201230
with open(filename, 'r') as file_obj:
202231
client_credentials = json.load(file_obj)
203-
return cls._from_parsed_json_keyfile(client_credentials, scopes)
232+
return cls._from_parsed_json_keyfile(client_credentials, scopes,
233+
token_uri=token_uri,
234+
revoke_uri=revoke_uri)
204235

205236
@classmethod
206-
def from_json_keyfile_dict(cls, keyfile_dict, scopes=''):
237+
def from_json_keyfile_dict(cls, keyfile_dict, scopes='',
238+
token_uri=None, revoke_uri=None):
207239
"""Factory constructor from parsed JSON keyfile.
208240
209241
Args:
210242
keyfile_dict: dict-like object, The parsed dictionary-like object
211243
containing the contents of the JSON keyfile.
212244
scopes: List or string, (Optional) Scopes to use when acquiring an
213245
access token.
246+
token_uri: string, URI for OAuth 2.0 provider token endpoint.
247+
If unset and not present in keyfile_dict, defaults
248+
to Google's endpoints.
249+
revoke_uri: string, URI for OAuth 2.0 provider revoke endpoint.
250+
If unset and not present in keyfile_dict, defaults
251+
to Google's endpoints.
214252
215253
Returns:
216254
ServiceAccountCredentials, a credentials object created from
@@ -221,12 +259,16 @@ def from_json_keyfile_dict(cls, keyfile_dict, scopes=''):
221259
KeyError, if one of the expected keys is not present in
222260
the keyfile.
223261
"""
224-
return cls._from_parsed_json_keyfile(keyfile_dict, scopes)
262+
return cls._from_parsed_json_keyfile(keyfile_dict, scopes,
263+
token_uri=token_uri,
264+
revoke_uri=revoke_uri)
225265

226266
@classmethod
227267
def _from_p12_keyfile_contents(cls, service_account_email,
228268
private_key_pkcs12,
229-
private_key_password=None, scopes=''):
269+
private_key_password=None, scopes='',
270+
token_uri=GOOGLE_TOKEN_URI,
271+
revoke_uri=GOOGLE_REVOKE_URI):
230272
"""Factory constructor from JSON keyfile.
231273
232274
Args:
@@ -237,6 +279,12 @@ def _from_p12_keyfile_contents(cls, service_account_email,
237279
private key. Defaults to ``notasecret``.
238280
scopes: List or string, (Optional) Scopes to use when acquiring an
239281
access token.
282+
token_uri: string, URI for token endpoint. For convenience defaults
283+
to Google's endpoints but any OAuth 2.0 provider can be
284+
used.
285+
revoke_uri: string, URI for revoke endpoint. For convenience
286+
defaults to Google's endpoints but any OAuth 2.0
287+
provider can be used.
240288
241289
Returns:
242290
ServiceAccountCredentials, a credentials object created from
@@ -252,14 +300,18 @@ def _from_p12_keyfile_contents(cls, service_account_email,
252300
raise NotImplementedError(_PKCS12_ERROR)
253301
signer = crypt.Signer.from_string(private_key_pkcs12,
254302
private_key_password)
255-
credentials = cls(service_account_email, signer, scopes=scopes)
303+
credentials = cls(service_account_email, signer, scopes=scopes,
304+
token_uri=token_uri, revoke_uri=revoke_uri)
256305
credentials._private_key_pkcs12 = private_key_pkcs12
257306
credentials._private_key_password = private_key_password
258307
return credentials
259308

260309
@classmethod
261310
def from_p12_keyfile(cls, service_account_email, filename,
262-
private_key_password=None, scopes=''):
311+
private_key_password=None, scopes='',
312+
token_uri=GOOGLE_TOKEN_URI,
313+
revoke_uri=GOOGLE_REVOKE_URI):
314+
263315
"""Factory constructor from JSON keyfile.
264316
265317
Args:
@@ -270,6 +322,12 @@ def from_p12_keyfile(cls, service_account_email, filename,
270322
private key. Defaults to ``notasecret``.
271323
scopes: List or string, (Optional) Scopes to use when acquiring an
272324
access token.
325+
token_uri: string, URI for token endpoint. For convenience defaults
326+
to Google's endpoints but any OAuth 2.0 provider can be
327+
used.
328+
revoke_uri: string, URI for revoke endpoint. For convenience
329+
defaults to Google's endpoints but any OAuth 2.0
330+
provider can be used.
273331
274332
Returns:
275333
ServiceAccountCredentials, a credentials object created from
@@ -283,11 +341,14 @@ def from_p12_keyfile(cls, service_account_email, filename,
283341
private_key_pkcs12 = file_obj.read()
284342
return cls._from_p12_keyfile_contents(
285343
service_account_email, private_key_pkcs12,
286-
private_key_password=private_key_password, scopes=scopes)
344+
private_key_password=private_key_password, scopes=scopes,
345+
token_uri=token_uri, revoke_uri=revoke_uri)
287346

288347
@classmethod
289348
def from_p12_keyfile_buffer(cls, service_account_email, file_buffer,
290-
private_key_password=None, scopes=''):
349+
private_key_password=None, scopes='',
350+
token_uri=GOOGLE_TOKEN_URI,
351+
revoke_uri=GOOGLE_REVOKE_URI):
291352
"""Factory constructor from JSON keyfile.
292353
293354
Args:
@@ -299,6 +360,12 @@ def from_p12_keyfile_buffer(cls, service_account_email, file_buffer,
299360
private key. Defaults to ``notasecret``.
300361
scopes: List or string, (Optional) Scopes to use when acquiring an
301362
access token.
363+
token_uri: string, URI for token endpoint. For convenience defaults
364+
to Google's endpoints but any OAuth 2.0 provider can be
365+
used.
366+
revoke_uri: string, URI for revoke endpoint. For convenience
367+
defaults to Google's endpoints but any OAuth 2.0
368+
provider can be used.
302369
303370
Returns:
304371
ServiceAccountCredentials, a credentials object created from
@@ -311,7 +378,8 @@ def from_p12_keyfile_buffer(cls, service_account_email, file_buffer,
311378
private_key_pkcs12 = file_buffer.read()
312379
return cls._from_p12_keyfile_contents(
313380
service_account_email, private_key_pkcs12,
314-
private_key_password=private_key_password, scopes=scopes)
381+
private_key_password=private_key_password, scopes=scopes,
382+
token_uri=token_uri, revoke_uri=revoke_uri)
315383

316384
def _generate_assertion(self):
317385
"""Generate the assertion that will be used in the request."""
@@ -508,6 +576,8 @@ def __init__(self,
508576
private_key_id=None,
509577
client_id=None,
510578
user_agent=None,
579+
token_uri=GOOGLE_TOKEN_URI,
580+
revoke_uri=GOOGLE_REVOKE_URI,
511581
additional_claims=None):
512582
if additional_claims is None:
513583
additional_claims = {}
@@ -517,6 +587,8 @@ def __init__(self,
517587
private_key_id=private_key_id,
518588
client_id=client_id,
519589
user_agent=user_agent,
590+
token_uri=token_uri,
591+
revoke_uri=revoke_uri,
520592
**additional_claims)
521593

522594
def authorize(self, http):
@@ -595,17 +667,18 @@ def create_scoped_required(self):
595667
# JWTAccessCredentials are unscoped by definition
596668
return True
597669

598-
def create_scoped(self, scopes):
670+
def create_scoped(self, scopes, token_uri=GOOGLE_TOKEN_URI,
671+
revoke_uri=GOOGLE_REVOKE_URI):
599672
# Returns an OAuth2 credentials with the given scope
600673
result = ServiceAccountCredentials(self._service_account_email,
601674
self._signer,
602675
scopes=scopes,
603676
private_key_id=self._private_key_id,
604677
client_id=self.client_id,
605678
user_agent=self._user_agent,
679+
token_uri=token_uri,
680+
revoke_uri=revoke_uri,
606681
**self._kwargs)
607-
result.token_uri = self.token_uri
608-
result.revoke_uri = self.revoke_uri
609682
if self._private_key_pkcs8_pem is not None:
610683
result._private_key_pkcs8_pem = self._private_key_pkcs8_pem
611684
if self._private_key_pkcs12 is not None:

0 commit comments

Comments
 (0)