2424from firebase_admin import _user_identifier
2525from firebase_admin import _user_import
2626from firebase_admin import _user_mgt
27+ from firebase_admin import _utils
2728
2829
2930class Client :
@@ -36,17 +37,37 @@ def __init__(self, app, tenant_id=None):
3637 2. set the project ID explicitly via Firebase App options, or
3738 3. set the project ID via the GOOGLE_CLOUD_PROJECT environment variable.""" )
3839
39- credential = app . credential . get_credential ()
40+ credential = None
4041 version_header = 'Python/Admin/{0}' .format (firebase_admin .__version__ )
42+ timeout = app .options .get ('httpTimeout' , _http_client .DEFAULT_TIMEOUT_SECONDS )
43+ # Non-default endpoint URLs for emulator support are set in this dict later.
44+ endpoint_urls = {}
45+ self .emulated = False
46+
47+ # If an emulator is present, check that the given value matches the expected format and set
48+ # endpoint URLs to use the emulator. Additionally, use a fake credential.
49+ emulator_host = _auth_utils .get_emulator_host ()
50+ if emulator_host :
51+ base_url = 'http://{0}/identitytoolkit.googleapis.com' .format (emulator_host )
52+ endpoint_urls ['v1' ] = base_url + '/v1'
53+ endpoint_urls ['v2beta1' ] = base_url + '/v2beta1'
54+ credential = _utils .EmulatorAdminCredentials ()
55+ self .emulated = True
56+ else :
57+ # Use credentials if provided
58+ credential = app .credential .get_credential ()
59+
4160 http_client = _http_client .JsonHttpClient (
42- credential = credential , headers = {'X-Client-Version' : version_header })
61+ credential = credential , headers = {'X-Client-Version' : version_header }, timeout = timeout )
4362
4463 self ._tenant_id = tenant_id
45- self ._token_generator = _token_gen .TokenGenerator (app , http_client )
64+ self ._token_generator = _token_gen .TokenGenerator (
65+ app , http_client , url_override = endpoint_urls .get ('v1' ))
4666 self ._token_verifier = _token_gen .TokenVerifier (app )
47- self ._user_manager = _user_mgt .UserManager (http_client , app .project_id , tenant_id )
67+ self ._user_manager = _user_mgt .UserManager (
68+ http_client , app .project_id , tenant_id , url_override = endpoint_urls .get ('v1' ))
4869 self ._provider_manager = _auth_providers .ProviderConfigClient (
49- http_client , app .project_id , tenant_id )
70+ http_client , app .project_id , tenant_id , url_override = endpoint_urls . get ( 'v2beta1' ) )
5071
5172 @property
5273 def tenant_id (self ):
@@ -79,7 +100,8 @@ def verify_id_token(self, id_token, check_revoked=False):
79100
80101 Args:
81102 id_token: A string of the encoded JWT.
82- check_revoked: Boolean, If true, checks whether the token has been revoked (optional).
103+ check_revoked: Boolean, If true, checks whether the token has been revoked or
104+ the user disabled (optional).
83105
84106 Returns:
85107 dict: A dictionary of key-value pairs parsed from the decoded JWT.
@@ -94,6 +116,8 @@ def verify_id_token(self, id_token, check_revoked=False):
94116 this ``Client`` instance.
95117 CertificateFetchError: If an error occurs while fetching the public key certificates
96118 required to verify the ID token.
119+ UserDisabledError: If ``check_revoked`` is ``True`` and the corresponding user
120+ record is disabled.
97121 """
98122 if not isinstance (check_revoked , bool ):
99123 # guard against accidental wrong assignment.
@@ -108,7 +132,8 @@ def verify_id_token(self, id_token, check_revoked=False):
108132 'Invalid tenant ID: {0}' .format (token_tenant_id ))
109133
110134 if check_revoked :
111- self ._check_jwt_revoked (verified_claims , _token_gen .RevokedIdTokenError , 'ID token' )
135+ self ._check_jwt_revoked_or_disabled (
136+ verified_claims , _token_gen .RevokedIdTokenError , 'ID token' )
112137 return verified_claims
113138
114139 def revoke_refresh_tokens (self , uid ):
@@ -160,7 +185,7 @@ def get_user_by_email(self, email):
160185
161186 Raises:
162187 ValueError: If the email is None, empty or malformed.
163- UserNotFoundError: If no user exists by the specified email address.
188+ UserNotFoundError: If no user exists for the specified email address.
164189 FirebaseError: If an error occurs while retrieving the user.
165190 """
166191 response = self ._user_manager .get_user (email = email )
@@ -177,7 +202,7 @@ def get_user_by_phone_number(self, phone_number):
177202
178203 Raises:
179204 ValueError: If the phone number is ``None``, empty or malformed.
180- UserNotFoundError: If no user exists by the specified phone number.
205+ UserNotFoundError: If no user exists for the specified phone number.
181206 FirebaseError: If an error occurs while retrieving the user.
182207 """
183208 response = self ._user_manager .get_user (phone_number = phone_number )
@@ -423,6 +448,7 @@ def generate_password_reset_link(self, email, action_code_settings=None):
423448
424449 Raises:
425450 ValueError: If the provided arguments are invalid
451+ EmailNotFoundError: If no user exists for the specified email address.
426452 FirebaseError: If an error occurs while generating the link
427453 """
428454 return self ._user_manager .generate_email_action_link (
@@ -443,6 +469,7 @@ def generate_email_verification_link(self, email, action_code_settings=None):
443469
444470 Raises:
445471 ValueError: If the provided arguments are invalid
472+ UserNotFoundError: If no user exists for the specified email address.
446473 FirebaseError: If an error occurs while generating the link
447474 """
448475 return self ._user_manager .generate_email_action_link (
@@ -697,7 +724,9 @@ def list_saml_provider_configs(
697724 """
698725 return self ._provider_manager .list_saml_provider_configs (page_token , max_results )
699726
700- def _check_jwt_revoked (self , verified_claims , exc_type , label ):
727+ def _check_jwt_revoked_or_disabled (self , verified_claims , exc_type , label ):
701728 user = self .get_user (verified_claims .get ('uid' ))
729+ if user .disabled :
730+ raise _auth_utils .UserDisabledError ('The user record is disabled.' )
702731 if verified_claims .get ('iat' ) * 1000 < user .tokens_valid_after_timestamp :
703732 raise exc_type ('The Firebase {0} has been revoked.' .format (label ))
0 commit comments