Skip to content

Commit 71d33c0

Browse files
authored
Moved all public auth APIs to _AuthClient (#430)
1 parent 5b349b8 commit 71d33c0

File tree

3 files changed

+114
-77
lines changed

3 files changed

+114
-77
lines changed

firebase_admin/auth.py

Lines changed: 107 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ def create_custom_token(uid, developer_claims=None, app=None):
145145
ValueError: If input parameters are invalid.
146146
TokenSignError: If an error occurs while signing the token using the remote IAM service.
147147
"""
148-
token_generator = _get_auth_service(app).token_generator
149-
return token_generator.create_custom_token(uid, developer_claims)
148+
service = _get_auth_service(app)
149+
return service.create_custom_token(uid, developer_claims)
150150

151151

152152
def verify_id_token(id_token, app=None, check_revoked=False):
@@ -171,15 +171,8 @@ def verify_id_token(id_token, app=None, check_revoked=False):
171171
CertificateFetchError: If an error occurs while fetching the public key certificates
172172
required to verify the ID token.
173173
"""
174-
if not isinstance(check_revoked, bool):
175-
# guard against accidental wrong assignment.
176-
raise ValueError('Illegal check_revoked argument. Argument must be of type '
177-
' bool, but given "{0}".'.format(type(check_revoked)))
178-
token_verifier = _get_auth_service(app).token_verifier
179-
verified_claims = token_verifier.verify_id_token(id_token)
180-
if check_revoked:
181-
_check_jwt_revoked(verified_claims, RevokedIdTokenError, 'ID token', app)
182-
return verified_claims
174+
service = _get_auth_service(app)
175+
return service.verify_id_token(id_token, check_revoked=check_revoked)
183176

184177

185178
def create_session_cookie(id_token, expires_in, app=None):
@@ -200,8 +193,9 @@ def create_session_cookie(id_token, expires_in, app=None):
200193
ValueError: If input parameters are invalid.
201194
FirebaseError: If an error occurs while creating the cookie.
202195
"""
203-
token_generator = _get_auth_service(app).token_generator
204-
return token_generator.create_session_cookie(id_token, expires_in)
196+
service = _get_auth_service(app)
197+
# pylint: disable=protected-access
198+
return service._token_generator.create_session_cookie(id_token, expires_in)
205199

206200

207201
def verify_session_cookie(session_cookie, check_revoked=False, app=None):
@@ -226,10 +220,11 @@ def verify_session_cookie(session_cookie, check_revoked=False, app=None):
226220
CertificateFetchError: If an error occurs while fetching the public key certificates
227221
required to verify the session cookie.
228222
"""
229-
token_verifier = _get_auth_service(app).token_verifier
230-
verified_claims = token_verifier.verify_session_cookie(session_cookie)
223+
service = _get_auth_service(app)
224+
# pylint: disable=protected-access
225+
verified_claims = service._token_verifier.verify_session_cookie(session_cookie)
231226
if check_revoked:
232-
_check_jwt_revoked(verified_claims, RevokedSessionCookieError, 'session cookie', app)
227+
service._check_jwt_revoked(verified_claims, RevokedSessionCookieError, 'session cookie')
233228
return verified_claims
234229

235230

@@ -245,8 +240,8 @@ def revoke_refresh_tokens(uid, app=None):
245240
natural expiration (one hour). To verify that ID tokens are revoked, use
246241
``verify_id_token(idToken, check_revoked=True)``.
247242
"""
248-
user_manager = _get_auth_service(app).user_manager
249-
user_manager.update_user(uid, valid_since=int(time.time()))
243+
service = _get_auth_service(app)
244+
service.revoke_refresh_tokens(uid)
250245

251246

252247
def get_user(uid, app=None):
@@ -264,9 +259,8 @@ def get_user(uid, app=None):
264259
UserNotFoundError: If the specified user ID does not exist.
265260
FirebaseError: If an error occurs while retrieving the user.
266261
"""
267-
user_manager = _get_auth_service(app).user_manager
268-
response = user_manager.get_user(uid=uid)
269-
return UserRecord(response)
262+
service = _get_auth_service(app)
263+
return service.get_user(uid=uid)
270264

271265

272266
def get_user_by_email(email, app=None):
@@ -284,9 +278,8 @@ def get_user_by_email(email, app=None):
284278
UserNotFoundError: If no user exists by the specified email address.
285279
FirebaseError: If an error occurs while retrieving the user.
286280
"""
287-
user_manager = _get_auth_service(app).user_manager
288-
response = user_manager.get_user(email=email)
289-
return UserRecord(response)
281+
service = _get_auth_service(app)
282+
return service.get_user_by_email(email=email)
290283

291284

292285
def get_user_by_phone_number(phone_number, app=None):
@@ -304,9 +297,8 @@ def get_user_by_phone_number(phone_number, app=None):
304297
UserNotFoundError: If no user exists by the specified phone number.
305298
FirebaseError: If an error occurs while retrieving the user.
306299
"""
307-
user_manager = _get_auth_service(app).user_manager
308-
response = user_manager.get_user(phone_number=phone_number)
309-
return UserRecord(response)
300+
service = _get_auth_service(app)
301+
return service.get_user_by_phone_number(phone_number=phone_number)
310302

311303

312304
def list_users(page_token=None, max_results=_user_mgt.MAX_LIST_USERS_RESULTS, app=None):
@@ -331,10 +323,8 @@ def list_users(page_token=None, max_results=_user_mgt.MAX_LIST_USERS_RESULTS, ap
331323
ValueError: If max_results or page_token are invalid.
332324
FirebaseError: If an error occurs while retrieving the user accounts.
333325
"""
334-
user_manager = _get_auth_service(app).user_manager
335-
def download(page_token, max_results):
336-
return user_manager.list_users(page_token, max_results)
337-
return ListUsersPage(download, page_token, max_results)
326+
service = _get_auth_service(app)
327+
return service.list_users(page_token=page_token, max_results=max_results)
338328

339329

340330
def create_user(**kwargs): # pylint: disable=differing-param-doc
@@ -363,9 +353,8 @@ def create_user(**kwargs): # pylint: disable=differing-param-doc
363353
FirebaseError: If an error occurs while creating the user account.
364354
"""
365355
app = kwargs.pop('app', None)
366-
user_manager = _get_auth_service(app).user_manager
367-
uid = user_manager.create_user(**kwargs)
368-
return UserRecord(user_manager.get_user(uid=uid))
356+
service = _get_auth_service(app)
357+
return service.create_user(**kwargs)
369358

370359

371360
def update_user(uid, **kwargs): # pylint: disable=differing-param-doc
@@ -400,9 +389,8 @@ def update_user(uid, **kwargs): # pylint: disable=differing-param-doc
400389
FirebaseError: If an error occurs while updating the user account.
401390
"""
402391
app = kwargs.pop('app', None)
403-
user_manager = _get_auth_service(app).user_manager
404-
user_manager.update_user(uid, **kwargs)
405-
return UserRecord(user_manager.get_user(uid=uid))
392+
service = _get_auth_service(app)
393+
return service.update_user(uid, **kwargs)
406394

407395

408396
def set_custom_user_claims(uid, custom_claims, app=None):
@@ -425,10 +413,8 @@ def set_custom_user_claims(uid, custom_claims, app=None):
425413
ValueError: If the specified user ID or the custom claims are invalid.
426414
FirebaseError: If an error occurs while updating the user account.
427415
"""
428-
user_manager = _get_auth_service(app).user_manager
429-
if custom_claims is None:
430-
custom_claims = DELETE_ATTRIBUTE
431-
user_manager.update_user(uid, custom_claims=custom_claims)
416+
service = _get_auth_service(app)
417+
service.set_custom_user_claims(uid, custom_claims=custom_claims)
432418

433419

434420
def delete_user(uid, app=None):
@@ -442,8 +428,8 @@ def delete_user(uid, app=None):
442428
ValueError: If the user ID is None, empty or malformed.
443429
FirebaseError: If an error occurs while deleting the user account.
444430
"""
445-
user_manager = _get_auth_service(app).user_manager
446-
user_manager.delete_user(uid)
431+
service = _get_auth_service(app)
432+
service.delete_user(uid)
447433

448434

449435
def import_users(users, hash_alg=None, app=None):
@@ -468,9 +454,8 @@ def import_users(users, hash_alg=None, app=None):
468454
ValueError: If the provided arguments are invalid.
469455
FirebaseError: If an error occurs while importing users.
470456
"""
471-
user_manager = _get_auth_service(app).user_manager
472-
result = user_manager.import_users(users, hash_alg)
473-
return UserImportResult(result, len(users))
457+
service = _get_auth_service(app)
458+
return service.import_users(users, hash_alg)
474459

475460

476461
def generate_password_reset_link(email, action_code_settings=None, app=None):
@@ -490,9 +475,8 @@ def generate_password_reset_link(email, action_code_settings=None, app=None):
490475
ValueError: If the provided arguments are invalid
491476
FirebaseError: If an error occurs while generating the link
492477
"""
493-
user_manager = _get_auth_service(app).user_manager
494-
return user_manager.generate_email_action_link(
495-
'PASSWORD_RESET', email, action_code_settings=action_code_settings)
478+
service = _get_auth_service(app)
479+
return service.generate_password_reset_link(email, action_code_settings=action_code_settings)
496480

497481

498482
def generate_email_verification_link(email, action_code_settings=None, app=None):
@@ -512,9 +496,9 @@ def generate_email_verification_link(email, action_code_settings=None, app=None)
512496
ValueError: If the provided arguments are invalid
513497
FirebaseError: If an error occurs while generating the link
514498
"""
515-
user_manager = _get_auth_service(app).user_manager
516-
return user_manager.generate_email_action_link(
517-
'VERIFY_EMAIL', email, action_code_settings=action_code_settings)
499+
service = _get_auth_service(app)
500+
return service.generate_email_verification_link(
501+
email, action_code_settings=action_code_settings)
518502

519503

520504
def generate_sign_in_with_email_link(email, action_code_settings, app=None):
@@ -534,15 +518,9 @@ def generate_sign_in_with_email_link(email, action_code_settings, app=None):
534518
ValueError: If the provided arguments are invalid
535519
FirebaseError: If an error occurs while generating the link
536520
"""
537-
user_manager = _get_auth_service(app).user_manager
538-
return user_manager.generate_email_action_link(
539-
'EMAIL_SIGNIN', email, action_code_settings=action_code_settings)
540-
541-
542-
def _check_jwt_revoked(verified_claims, exc_type, label, app):
543-
user = get_user(verified_claims.get('uid'), app=app)
544-
if verified_claims.get('iat') * 1000 < user.tokens_valid_after_timestamp:
545-
raise exc_type('The Firebase {0} has been revoked.'.format(label))
521+
service = _get_auth_service(app)
522+
return service.generate_sign_in_with_email_link(
523+
email, action_code_settings=action_code_settings)
546524

547525

548526
class _AuthService:
@@ -567,14 +545,73 @@ def __init__(self, app):
567545
self._token_verifier = _token_gen.TokenVerifier(app)
568546
self._user_manager = _user_mgt.UserManager(client)
569547

570-
@property
571-
def token_generator(self):
572-
return self._token_generator
548+
def create_custom_token(self, uid, developer_claims=None):
549+
return self._token_generator.create_custom_token(uid, developer_claims)
550+
551+
def verify_id_token(self, id_token, check_revoked=False):
552+
if not isinstance(check_revoked, bool):
553+
# guard against accidental wrong assignment.
554+
raise ValueError('Illegal check_revoked argument. Argument must be of type '
555+
' bool, but given "{0}".'.format(type(check_revoked)))
556+
557+
verified_claims = self._token_verifier.verify_id_token(id_token)
558+
if check_revoked:
559+
self._check_jwt_revoked(verified_claims, RevokedIdTokenError, 'ID token')
560+
return verified_claims
561+
562+
def revoke_refresh_tokens(self, uid):
563+
self._user_manager.update_user(uid, valid_since=int(time.time()))
564+
565+
def get_user(self, uid):
566+
response = self._user_manager.get_user(uid=uid)
567+
return UserRecord(response)
568+
569+
def get_user_by_email(self, email):
570+
response = self._user_manager.get_user(email=email)
571+
return UserRecord(response)
572+
573+
def get_user_by_phone_number(self, phone_number):
574+
response = self._user_manager.get_user(phone_number=phone_number)
575+
return UserRecord(response)
576+
577+
def list_users(self, page_token=None, max_results=_user_mgt.MAX_LIST_USERS_RESULTS):
578+
def download(page_token, max_results):
579+
return self._user_manager.list_users(page_token, max_results)
580+
return ListUsersPage(download, page_token, max_results)
581+
582+
def create_user(self, **kwargs):
583+
uid = self._user_manager.create_user(**kwargs)
584+
return self.get_user(uid=uid)
585+
586+
def update_user(self, uid, **kwargs):
587+
self._user_manager.update_user(uid, **kwargs)
588+
return self.get_user(uid=uid)
589+
590+
def set_custom_user_claims(self, uid, custom_claims):
591+
if custom_claims is None:
592+
custom_claims = DELETE_ATTRIBUTE
593+
self._user_manager.update_user(uid, custom_claims=custom_claims)
594+
595+
def delete_user(self, uid):
596+
self._user_manager.delete_user(uid)
597+
598+
def import_users(self, users, hash_alg=None):
599+
result = self._user_manager.import_users(users, hash_alg)
600+
return UserImportResult(result, len(users))
601+
602+
def generate_password_reset_link(self, email, action_code_settings=None):
603+
return self._user_manager.generate_email_action_link(
604+
'PASSWORD_RESET', email, action_code_settings=action_code_settings)
605+
606+
def generate_email_verification_link(self, email, action_code_settings=None):
607+
return self._user_manager.generate_email_action_link(
608+
'VERIFY_EMAIL', email, action_code_settings=action_code_settings)
573609

574-
@property
575-
def token_verifier(self):
576-
return self._token_verifier
610+
def generate_sign_in_with_email_link(self, email, action_code_settings):
611+
return self._user_manager.generate_email_action_link(
612+
'EMAIL_SIGNIN', email, action_code_settings=action_code_settings)
577613

578-
@property
579-
def user_manager(self):
580-
return self._user_manager
614+
def _check_jwt_revoked(self, verified_claims, exc_type, label):
615+
user = self.get_user(verified_claims.get('uid'))
616+
if verified_claims.get('iat') * 1000 < user.tokens_valid_after_timestamp:
617+
raise exc_type('The Firebase {0} has been revoked.'.format(label))

tests/test_token_gen.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def _get_session_cookie(payload_overrides=None, header_overrides=None):
110110

111111
def _instrument_user_manager(app, status, payload):
112112
auth_service = auth._get_auth_service(app)
113-
user_manager = auth_service.user_manager
113+
user_manager = auth_service._user_manager
114114
recorder = []
115115
user_manager._client.session.mount(
116116
auth._AuthService.ID_TOOLKIT_URL,
@@ -119,11 +119,11 @@ def _instrument_user_manager(app, status, payload):
119119

120120
def _overwrite_cert_request(app, request):
121121
auth_service = auth._get_auth_service(app)
122-
auth_service.token_verifier.request = request
122+
auth_service._token_verifier.request = request
123123

124124
def _overwrite_iam_request(app, request):
125125
auth_service = auth._get_auth_service(app)
126-
auth_service.token_generator.request = request
126+
auth_service._token_generator.request = request
127127

128128
@pytest.fixture(scope='module')
129129
def auth_app():
@@ -246,7 +246,7 @@ def test_sign_with_discovered_service_account(self):
246246
_overwrite_iam_request(app, request)
247247
# Force initialization of the signing provider. This will invoke the Metadata service.
248248
auth_service = auth._get_auth_service(app)
249-
assert auth_service.token_generator.signing_provider is not None
249+
assert auth_service._token_generator.signing_provider is not None
250250
# Now invoke the IAM signer.
251251
signature = base64.b64encode(b'test').decode()
252252
request.response = testutils.MockResponse(

tests/test_user_mgt.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def user_mgt_app():
5959

6060
def _instrument_user_manager(app, status, payload):
6161
auth_service = auth._get_auth_service(app)
62-
user_manager = auth_service.user_manager
62+
user_manager = auth_service._user_manager
6363
recorder = []
6464
user_manager._client.session.mount(
6565
auth._AuthService.ID_TOOLKIT_URL,
@@ -105,7 +105,7 @@ class TestAuthServiceInitialization:
105105

106106
def test_default_timeout(self, user_mgt_app):
107107
auth_service = auth._get_auth_service(user_mgt_app)
108-
user_manager = auth_service.user_manager
108+
user_manager = auth_service._user_manager
109109
assert user_manager._client.timeout == _http_client.DEFAULT_TIMEOUT_SECONDS
110110

111111
def test_fail_on_no_project_id(self):
@@ -1302,7 +1302,7 @@ def test_bad_settings_data(self, user_mgt_app, func):
13021302
def test_bad_action_type(self, user_mgt_app):
13031303
with pytest.raises(ValueError):
13041304
auth._get_auth_service(user_mgt_app) \
1305-
.user_manager \
1305+
._user_manager \
13061306
.generate_email_action_link('BAD_TYPE', '[email protected]',
13071307
action_code_settings=MOCK_ACTION_CODE_SETTINGS)
13081308

0 commit comments

Comments
 (0)