Skip to content

Commit 09c3c98

Browse files
committed
Merge pull request #1479 from dhermes/oauth2client-2.0
Upgrading to oauth2client 2.0.
2 parents dc26221 + b6725d7 commit 09c3c98

File tree

3 files changed

+88
-121
lines changed

3 files changed

+88
-121
lines changed

gcloud/credentials.py

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from oauth2client import client
3030
from oauth2client.client import _get_application_default_credential_from_file
3131
from oauth2client import crypt
32-
from oauth2client import service_account
32+
from oauth2client.service_account import ServiceAccountCredentials
3333
try:
3434
from oauth2client.appengine import AppAssertionCredentials as _GAECreds
3535
except ImportError:
@@ -95,7 +95,7 @@ def get_credentials():
9595
:rtype: :class:`oauth2client.client.GoogleCredentials`,
9696
:class:`oauth2client.contrib.appengine.AppAssertionCredentials`,
9797
:class:`oauth2client.contrib.gce.AppAssertionCredentials`,
98-
:class:`oauth2client.service_account._ServiceAccountCredentials`
98+
:class:`oauth2client.service_account.ServiceAccountCredentials`
9999
:returns: A new credentials instance corresponding to the implicit
100100
environment.
101101
"""
@@ -120,7 +120,7 @@ def get_for_service_account_json(json_credentials_path, scope=None):
120120
particular API.)
121121
122122
:rtype: :class:`oauth2client.client.GoogleCredentials`,
123-
:class:`oauth2client.service_account._ServiceAccountCredentials`
123+
:class:`oauth2client.service_account.ServiceAccountCredentials`
124124
:returns: New service account or Google (for a user JSON key file)
125125
credentials object.
126126
"""
@@ -154,21 +154,18 @@ def get_for_service_account_p12(client_email, private_key_path, scope=None):
154154
scope is required for the different levels of access to any
155155
particular API.)
156156
157-
:rtype: :class:`oauth2client.client.SignedJwtAssertionCredentials`
158-
:returns: A new ``SignedJwtAssertionCredentials`` instance with the
157+
:rtype: :class:`oauth2client.service_account.ServiceAccountCredentials`
158+
:returns: A new ``ServiceAccountCredentials`` instance with the
159159
needed service account settings.
160160
"""
161-
return client.SignedJwtAssertionCredentials(
162-
service_account_name=client_email,
163-
private_key=open(private_key_path, 'rb').read(),
164-
scope=scope)
161+
return ServiceAccountCredentials.from_p12_keyfile(
162+
client_email, private_key_path, scopes=scope)
165163

166164

167165
def _get_pem_key(credentials):
168166
"""Gets private key for a PEM payload from a credentials object.
169167
170-
:type credentials: :class:`client.SignedJwtAssertionCredentials`,
171-
:class:`service_account._ServiceAccountCredentials`
168+
:type credentials: :class:`service_account.ServiceAccountCredentials`,
172169
:param credentials: The credentials used to create a private key
173170
for signing text.
174171
@@ -177,12 +174,14 @@ def _get_pem_key(credentials):
177174
:raises: `TypeError` if `credentials` is the wrong type.
178175
`EnvironmentError` if `crypto` did not import successfully.
179176
"""
180-
if isinstance(credentials, client.SignedJwtAssertionCredentials):
181-
# Take our PKCS12 (.p12) text and convert to PEM text.
182-
pem_text = crypt.pkcs12_key_as_pem(credentials.private_key,
183-
credentials.private_key_password)
184-
elif isinstance(credentials, service_account._ServiceAccountCredentials):
185-
pem_text = credentials._private_key_pkcs8_text
177+
if isinstance(credentials, ServiceAccountCredentials):
178+
if credentials._private_key_pkcs12 is not None:
179+
# Take our PKCS12 (.p12) text and convert to PEM text.
180+
pem_text = crypt.pkcs12_key_as_pem(
181+
credentials._private_key_pkcs12,
182+
credentials._private_key_password)
183+
else:
184+
pem_text = credentials._private_key_pkcs8_pem
186185
else:
187186
raise TypeError((credentials,
188187
'not a valid service account credentials type'))
@@ -196,8 +195,7 @@ def _get_pem_key(credentials):
196195
def _get_signature_bytes(credentials, string_to_sign):
197196
"""Uses crypto attributes of credentials to sign a string/bytes.
198197
199-
:type credentials: :class:`client.SignedJwtAssertionCredentials`,
200-
:class:`service_account._ServiceAccountCredentials`,
198+
:type credentials: :class:`service_account.ServiceAccountCredentials`,
201199
:class:`_GAECreds`
202200
:param credentials: The credentials used for signing text (typically
203201
involves the creation of a PKey).
@@ -227,8 +225,7 @@ def _get_signature_bytes(credentials, string_to_sign):
227225
def _get_service_account_name(credentials):
228226
"""Determines service account name from a credentials object.
229227
230-
:type credentials: :class:`client.SignedJwtAssertionCredentials`,
231-
:class:`service_account._ServiceAccountCredentials`,
228+
:type credentials: :class:`service_account.ServiceAccountCredentials`,
232229
:class:`_GAECreds`
233230
:param credentials: The credentials used to determine the service
234231
account name.
@@ -239,10 +236,8 @@ def _get_service_account_name(credentials):
239236
account type.
240237
"""
241238
service_account_name = None
242-
if isinstance(credentials, client.SignedJwtAssertionCredentials):
243-
service_account_name = credentials.service_account_name
244-
elif isinstance(credentials, service_account._ServiceAccountCredentials):
245-
service_account_name = credentials._service_account_email
239+
if isinstance(credentials, ServiceAccountCredentials):
240+
service_account_name = credentials.service_account_email
246241
elif isinstance(credentials, _GAECreds):
247242
service_account_name = app_identity.get_service_account_name()
248243

@@ -255,8 +250,7 @@ def _get_service_account_name(credentials):
255250
def _get_signed_query_params(credentials, expiration, string_to_sign):
256251
"""Gets query parameters for creating a signed URL.
257252
258-
:type credentials: :class:`client.SignedJwtAssertionCredentials`,
259-
:class:`service_account._ServiceAccountCredentials`
253+
:type credentials: :class:`service_account.ServiceAccountCredentials`
260254
:param credentials: The credentials used to create a private key
261255
for signing text.
262256

gcloud/test_credentials.py

Lines changed: 66 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -90,47 +90,31 @@ def _callFUT(self, client_email, private_key_path, scope=None):
9090
def test_it(self):
9191
from gcloud import credentials as MUT
9292
from gcloud._testing import _Monkey
93-
from gcloud._testing import _NamedTemporaryFile
9493

9594
CLIENT_EMAIL = 'phred@example.com'
96-
PRIVATE_KEY = b'SEEkR1t'
97-
client = _Client()
98-
with _Monkey(MUT, client=client):
99-
with _NamedTemporaryFile() as temp:
100-
with open(temp.name, 'wb') as file_obj:
101-
file_obj.write(PRIVATE_KEY)
102-
found = self._callFUT(CLIENT_EMAIL, temp.name)
95+
MOCK_FILENAME = 'foo.path'
96+
MOCK_CRED_CLASS = _MockServiceAccountCredentials()
97+
with _Monkey(MUT, ServiceAccountCredentials=MOCK_CRED_CLASS):
98+
found = self._callFUT(CLIENT_EMAIL, MOCK_FILENAME)
10399

104-
self.assertTrue(found is client._signed)
105-
expected_called_with = {
106-
'service_account_name': CLIENT_EMAIL,
107-
'private_key': PRIVATE_KEY,
108-
'scope': None,
109-
}
110-
self.assertEqual(client._called_with, expected_called_with)
100+
self.assertTrue(found is MOCK_CRED_CLASS._result)
101+
self.assertEqual(MOCK_CRED_CLASS.p12_called,
102+
[(CLIENT_EMAIL, MOCK_FILENAME, None)])
111103

112104
def test_it_with_scope(self):
113105
from gcloud import credentials as MUT
114106
from gcloud._testing import _Monkey
115-
from gcloud._testing import _NamedTemporaryFile
116107

117108
CLIENT_EMAIL = 'phred@example.com'
118-
PRIVATE_KEY = b'SEEkR1t'
119109
SCOPE = 'SCOPE'
120-
client = _Client()
121-
with _Monkey(MUT, client=client):
122-
with _NamedTemporaryFile() as temp:
123-
with open(temp.name, 'wb') as file_obj:
124-
file_obj.write(PRIVATE_KEY)
125-
found = self._callFUT(CLIENT_EMAIL, temp.name, SCOPE)
110+
MOCK_FILENAME = 'foo.path'
111+
MOCK_CRED_CLASS = _MockServiceAccountCredentials()
112+
with _Monkey(MUT, ServiceAccountCredentials=MOCK_CRED_CLASS):
113+
found = self._callFUT(CLIENT_EMAIL, MOCK_FILENAME, SCOPE)
126114

127-
self.assertTrue(found is client._signed)
128-
expected_called_with = {
129-
'service_account_name': CLIENT_EMAIL,
130-
'private_key': PRIVATE_KEY,
131-
'scope': SCOPE,
132-
}
133-
self.assertEqual(client._called_with, expected_called_with)
115+
self.assertTrue(found is MOCK_CRED_CLASS._result)
116+
self.assertEqual(MOCK_CRED_CLASS.p12_called,
117+
[(CLIENT_EMAIL, MOCK_FILENAME, SCOPE)])
134118

135119

136120
class Test_get_for_service_account_json(unittest2.TestCase):
@@ -279,8 +263,7 @@ def _run_with_fake_crypto(self, credentials, private_key_text,
279263
result = self._callFUT(credentials, string_to_sign)
280264

281265
if crypt._pkcs12_key_as_pem_called:
282-
self.assertEqual(crypt._private_key_text,
283-
base64.b64encode(private_key_text))
266+
self.assertEqual(crypt._private_key_text, private_key_text)
284267
self.assertEqual(crypt._private_key_password, 'notasecret')
285268
self.assertEqual(openssl_crypto._loaded,
286269
[(openssl_crypto.FILETYPE_PEM, _Crypt._KEY)])
@@ -296,22 +279,28 @@ def _run_with_fake_crypto(self, credentials, private_key_text,
296279
self.assertEqual(result, sign_result)
297280

298281
def test_p12_type(self):
299-
from oauth2client.client import SignedJwtAssertionCredentials
282+
from oauth2client.service_account import ServiceAccountCredentials
300283
ACCOUNT_NAME = 'dummy_service_account_name'
301284
PRIVATE_KEY_TEXT = b'dummy_private_key_text'
302285
STRING_TO_SIGN = b'dummy_signature'
303-
CREDENTIALS = SignedJwtAssertionCredentials(
304-
ACCOUNT_NAME, PRIVATE_KEY_TEXT, [])
286+
SIGNER = object()
287+
CREDENTIALS = ServiceAccountCredentials(
288+
ACCOUNT_NAME, SIGNER)
289+
CREDENTIALS._private_key_pkcs12 = PRIVATE_KEY_TEXT
290+
CREDENTIALS._private_key_password = 'notasecret'
305291
self._run_with_fake_crypto(CREDENTIALS, PRIVATE_KEY_TEXT,
306292
STRING_TO_SIGN)
307293

308294
def test_p12_type_non_bytes_to_sign(self):
309-
from oauth2client.client import SignedJwtAssertionCredentials
295+
from oauth2client.service_account import ServiceAccountCredentials
310296
ACCOUNT_NAME = 'dummy_service_account_name'
311297
PRIVATE_KEY_TEXT = b'dummy_private_key_text'
312298
STRING_TO_SIGN = u'dummy_signature'
313-
CREDENTIALS = SignedJwtAssertionCredentials(
314-
ACCOUNT_NAME, PRIVATE_KEY_TEXT, [])
299+
SIGNER = object()
300+
CREDENTIALS = ServiceAccountCredentials(
301+
ACCOUNT_NAME, SIGNER)
302+
CREDENTIALS._private_key_pkcs12 = PRIVATE_KEY_TEXT
303+
CREDENTIALS._private_key_password = 'notasecret'
315304
self._run_with_fake_crypto(CREDENTIALS, PRIVATE_KEY_TEXT,
316305
STRING_TO_SIGN)
317306

@@ -321,21 +310,16 @@ def test_json_type(self):
321310

322311
PRIVATE_KEY_TEXT = 'dummy_private_key_pkcs8_text'
323312
STRING_TO_SIGN = b'dummy_signature'
324-
325-
def _get_private_key(private_key_pkcs8_text):
326-
return private_key_pkcs8_text
327-
328-
with _Monkey(service_account, _get_private_key=_get_private_key):
329-
CREDENTIALS = service_account._ServiceAccountCredentials(
330-
'dummy_service_account_id', 'dummy_service_account_email',
331-
'dummy_private_key_id', PRIVATE_KEY_TEXT, [])
332-
313+
SIGNER = object()
314+
CREDENTIALS = service_account.ServiceAccountCredentials(
315+
'dummy_service_account_email', SIGNER)
316+
CREDENTIALS._private_key_pkcs8_pem = PRIVATE_KEY_TEXT
333317
self._run_with_fake_crypto(CREDENTIALS, PRIVATE_KEY_TEXT,
334318
STRING_TO_SIGN)
335319

336320
def test_gae_type(self):
337321
# Relies on setUp fixing up App Engine imports.
338-
from oauth2client.appengine import AppAssertionCredentials
322+
from oauth2client.contrib.appengine import AppAssertionCredentials
339323
from gcloud._testing import _Monkey
340324
from gcloud import credentials
341325

@@ -387,33 +371,20 @@ def test_bad_type(self):
387371
None, None, None)
388372
self.assertRaises(ValueError, self._callFUT, CREDENTIALS)
389373

390-
def test_p12_type(self):
391-
from oauth2client.client import SignedJwtAssertionCredentials
392-
SERVICE_ACCOUNT_NAME = 'SERVICE_ACCOUNT_NAME'
393-
CREDENTIALS = SignedJwtAssertionCredentials(SERVICE_ACCOUNT_NAME,
394-
b'bogus_key', [])
395-
found = self._callFUT(CREDENTIALS)
396-
self.assertEqual(found, SERVICE_ACCOUNT_NAME)
397-
398-
def test_json_type(self):
374+
def test_service_account_type(self):
399375
from oauth2client import service_account
400-
from gcloud._testing import _Monkey
401-
402-
def _get_private_key(private_key_pkcs8_text):
403-
return private_key_pkcs8_text
404376

405377
SERVICE_ACCOUNT_NAME = 'SERVICE_ACCOUNT_NAME'
406-
with _Monkey(service_account, _get_private_key=_get_private_key):
407-
CREDENTIALS = service_account._ServiceAccountCredentials(
408-
'bogus_id', SERVICE_ACCOUNT_NAME, 'bogus_id',
409-
'bogus_key_text', [])
378+
SIGNER = object()
379+
CREDENTIALS = service_account.ServiceAccountCredentials(
380+
SERVICE_ACCOUNT_NAME, SIGNER)
410381

411382
found = self._callFUT(CREDENTIALS)
412383
self.assertEqual(found, SERVICE_ACCOUNT_NAME)
413384

414385
def test_gae_type(self):
415386
# Relies on setUp fixing up App Engine imports.
416-
from oauth2client.appengine import AppAssertionCredentials
387+
from oauth2client.contrib.appengine import AppAssertionCredentials
417388
from gcloud._testing import _Monkey
418389
from gcloud import credentials
419390

@@ -483,25 +454,26 @@ def test_bad_argument(self):
483454
self.assertRaises(TypeError, self._callFUT, None)
484455

485456
def test_signed_jwt_for_p12(self):
486-
import base64
487-
from oauth2client import client
457+
from oauth2client import service_account
488458
from gcloud._testing import _Monkey
489459
from gcloud import credentials as MUT
490460

491-
scopes = []
492461
PRIVATE_KEY = b'dummy_private_key_text'
493-
credentials = client.SignedJwtAssertionCredentials(
494-
'dummy_service_account_name', PRIVATE_KEY, scopes)
462+
SIGNER = object()
463+
credentials = service_account.ServiceAccountCredentials(
464+
'dummy_service_account_email', SIGNER)
465+
credentials._private_key_pkcs12 = PRIVATE_KEY
466+
credentials._private_key_password = password = 'password-nope'
467+
495468
crypt = _Crypt()
496469
load_result = object()
497470
openssl_crypto = _OpenSSLCrypto(load_result, None)
498471

499472
with _Monkey(MUT, crypt=crypt, crypto=openssl_crypto):
500473
result = self._callFUT(credentials)
501474

502-
self.assertEqual(crypt._private_key_text,
503-
base64.b64encode(PRIVATE_KEY))
504-
self.assertEqual(crypt._private_key_password, 'notasecret')
475+
self.assertEqual(crypt._private_key_text, PRIVATE_KEY)
476+
self.assertEqual(crypt._private_key_password, password)
505477
self.assertEqual(result, load_result)
506478
self.assertEqual(openssl_crypto._loaded,
507479
[(openssl_crypto.FILETYPE_PEM, _Crypt._KEY)])
@@ -515,14 +487,10 @@ def test_service_account_via_json_key(self):
515487
scopes = []
516488

517489
PRIVATE_TEXT = 'dummy_private_key_pkcs8_text'
518-
519-
def _get_private_key(private_key_pkcs8_text):
520-
return private_key_pkcs8_text
521-
522-
with _Monkey(service_account, _get_private_key=_get_private_key):
523-
credentials = service_account._ServiceAccountCredentials(
524-
'dummy_service_account_id', 'dummy_service_account_email',
525-
'dummy_private_key_id', PRIVATE_TEXT, scopes)
490+
SIGNER = object()
491+
credentials = service_account.ServiceAccountCredentials(
492+
'dummy_service_account_email', SIGNER, scopes=scopes)
493+
credentials._private_key_pkcs8_pem = PRIVATE_TEXT
526494

527495
load_result = object()
528496
openssl_crypto = _OpenSSLCrypto(load_result, None)
@@ -541,14 +509,11 @@ def test_without_pyopenssl(self):
541509
from gcloud import credentials as credentials_mod
542510

543511
PRIVATE_TEXT = 'dummy_private_key_pkcs8_text'
512+
SIGNER = object()
544513

545-
def _get_private_key(private_key_pkcs8_text):
546-
return private_key_pkcs8_text
547-
548-
with _Monkey(service_account, _get_private_key=_get_private_key):
549-
credentials = service_account._ServiceAccountCredentials(
550-
'dummy_service_account_id', 'dummy_service_account_email',
551-
'dummy_private_key_id', PRIVATE_TEXT, '')
514+
credentials = service_account.ServiceAccountCredentials(
515+
'dummy_service_account_email', SIGNER)
516+
credentials._private_key_pkcs8_pem = PRIVATE_TEXT
552517

553518
with _Monkey(credentials_mod, crypto=None):
554519
with self.assertRaises(EnvironmentError):
@@ -648,6 +613,7 @@ def create_scoped(self, scopes):
648613

649614

650615
class _Client(object):
616+
651617
def __init__(self):
652618
self._signed = _Credentials()
653619

@@ -659,10 +625,6 @@ def get_application_default():
659625

660626
self.GoogleCredentials = GoogleCredentials
661627

662-
def SignedJwtAssertionCredentials(self, **kw):
663-
self._called_with = kw
664-
return self._signed
665-
666628

667629
class _Crypt(object):
668630

@@ -724,3 +686,14 @@ def non_transactional(*args, **kwargs):
724686
def do_nothing_wrapper(func):
725687
return func
726688
return do_nothing_wrapper
689+
690+
691+
class _MockServiceAccountCredentials(object):
692+
693+
def __init__(self):
694+
self.p12_called = []
695+
self._result = _Credentials()
696+
697+
def from_p12_keyfile(self, email, path, scopes=None):
698+
self.p12_called.append((email, path, scopes))
699+
return self._result

0 commit comments

Comments
 (0)