8000 Migrated token_gen module to new error codes · SHavanonda/firebase-admin-python@1c093e2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1c093e2

Browse files
committed
Migrated token_gen module to new error codes
1 parent f2a1cd4 commit 1c093e2

File tree

5 files changed

+83
-77
lines changed

5 files changed

+83
-77
lines changed

firebase_admin/_auth_utils.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,25 @@ def __init__(self, code, message, cause=None, http_response=None, auth_error_cod
202202
@property
203203
def auth_error_code(self):
204204
return self._auth_error_code
205+
206+
207+
_ERROR_CODE_MAPPINGS = {
208+
'CLAIMS_TOO_LARGE': exceptions.INVALID_ARGUMENT,
209+
'INVALID_EMAIL': exceptions.INVALID_ARGUMENT,
210+
'INSUFFICIENT_PERMISSION': exceptions.PERMISSION_DENIED,
211+
'OPERATION_NOT_ALLOWED': exceptions.PERMISSION_DENIED,
212+
'PERMISSION_DENIED': exceptions.PERMISSION_DENIED,
213+
'USER_NOT_FOUND': exceptions.NOT_FOUND,
214+
'DUPLICATE_EMAIL': exceptions.ALREADY_EXISTS,
215+
}
216+
217+
218+
def handle_http_error(msg, error):
219+
response_payload = {}
220+
if error.response is not None:
221+
response_payload = error.response.json()
222+
msg += '\n Server response: {0}'.format(error.response.content.decode())
223+
server_code = response_payload.get('error', {}).get('message')
224+
canonical_code = _ERROR_CODE_MAPPINGS.get(server_code, exceptions.UNKNOWN)
225+
raise FirebaseAuthError(
226+
canonical_code, msg, cause=error, http_response=error.response, auth_error_code=server_code)

firebase_admin/_token_gen.py

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@
2020
import cachecontrol
2121
import requests
2222
import six
23+
import google.auth.exceptions
2324
from google.auth import credentials
24-
from google.auth import exceptions
2525
from google.auth import iam
2626
from google.auth import jwt
2727
from google.auth import transport
2828
import google.oauth2.id_token
2929
import google.oauth2.service_account
3030

31+
from firebase_admin import exceptions
32+
from firebase_admin import _auth_utils
33+
3134

3235
# ID token constants
3336
ID_TOKEN_ISSUER_PREFIX = 'https://securetoken.google.com/'
@@ -52,17 +55,8 @@
5255
'default/email')
5356

5457
# Error codes
55-
COOKIE_CREATE_ERROR = 'COOKIE_CREATE_ERROR'
56-
TOKEN_SIGN_ERROR = 'TOKEN_SIGN_ERROR'
57-
58-
59-
class ApiCallError(Exception):
60-
"""Represents an Exception encountered while invoking the ID toolkit API."""
61-
62-
def __init__(self, code, message, error=None):
63-
Exception.__init__(self, message)
64-
self.code = code
65-
self.detail = error
58+
TOKEN_SIGN_FAILED = 'TOKEN_SIGN_FAILED'
59+
CERTIFICATE_FETCH_FAILED = 'CERTIFICATE_FETCH_FAILED'
6660

6761

6862
class _SigningProvider(object):
@@ -177,9 +171,12 @@ def create_custom_token(self, uid, developer_claims=None):
177171
payload['claims'] = developer_claims
178172
try:
179173
return jwt.encode(signing_provider.signer, payload)
180-
except exceptions.TransportError as error:
181-
msg = 'Failed to sign custom token. {0}'.format(error)
182-
raise ApiCallError(TOKEN_SIGN_ERROR, msg, error)
174+
except google.auth.exceptions.TransportError as error:
175+
raise _auth_utils.FirebaseAuthError(
176+
exceptions.UNKNOWN,
177+
'Failed to sign custom token. {0}'.format(error),
178+
cause=error,
179+
auth_error_code=TOKEN_SIGN_FAILED)
183180

184181

185182
def create_session_cookie(self, id_token, expires_in):
@@ -206,20 +203,17 @@ def create_session_cookie(self, id_token, expires_in):
206203
'validDuration': expires_in,
207204
}
208205
try:
209-
response = self.client.body('post', ':createSessionCookie', json=payload)
206+
body, response = self.client.body_and_response('post', ':createSessionCookie', json=payload)
210207
except requests.exceptions.RequestException as error:
211-
self._handle_http_error(COOKIE_CREATE_ERROR, 'Failed to create session cookie', error)
208+
_auth_utils.handle_http_error('Failed to create session cookie', error)
212209
else:
213-
if not response or not response.get('sessionCookie'):
214-
raise ApiCallError(COOKIE_CREATE_ERROR, 'Failed to create session cookie.')
215-
return response.get('sessionCookie')
216-
217-
def _handle_http_error(self, code, msg, error):
218-
if error.response is not None:
219-
msg += '\nServer response: {0}'.format(error.response.content.decode())
220-
else:
221-
msg += '\nReason: {0}'.format(error)
222-
raise ApiCallError(code, msg, error)
210+
if not body or not body.get('sessionCookie'):
211+
raise _auth_utils.FirebaseAuthError(
212+
exceptions.UNKNOWN,
213+
'Failed to create session cookie.',
214+
http_response=response,
215+
auth_error_code='UNEXPECTED_RESPONSE')
216+
return body.get('sessionCookie')
223217

224218

225219
class TokenVerifier(object):
@@ -332,10 +326,18 @@ def verify(self, token, request):
332326
if error_message:
333327
raise ValueError(error_message)
334328

335-
verified_claims = google.oauth2.id_token.verify_token(
336-
token,
337-
request=request,
338-
audience=self.project_id,
339-
certs_url=self.cert_url)
340-
verified_claims['uid'] = verified_claims['sub']
341-
return verified_claims
329+
try:
330+
verified_claims = google.oauth2.id_token.verify_token(
331+
token,
332+
request=request,
333+
audience=self.project_id,
334+
certs_url=self.cert_url)
335+
verified_claims['uid'] = verified_claims['sub']
336+
return verified_claims
337+
except google.auth.exceptions.TransportError as error:
338+
raise _auth_utils.FirebaseAuthError(
339+
exceptions.UNKNOWN,
340+
'Failed to fetch public key certificates. {0}'.format(error),
341+
cause=error,
342+
auth_error_code=CERTIFICATE_FETCH_FAILED)
343+

firebase_admin/_user_mgt.py

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ def get_user(self, **kwargs):
469469
body, response = self._client.body_and_response('post', '/accounts:lookup', json=payload)
470470
except requests.exceptions.RequestException as error:
471471
msg = 'Failed to get user by {0}: {1}.'.format(key_type, key)
472-
self._handle_http_error(msg, error)
472+
_auth_utils.handle_http_error(msg, error)
473473
else:
474474
if not body or not body.get('users'):
475475
raise _auth_utils.FirebaseAuthError(
@@ -497,7 +497,7 @@ def list_users(self, page_token=None, max_results=MAX_LIST_USERS_RESULTS):
497497
try:
498498
return self._client.body('get', '/accounts:batchGet', params=payload)
499499
except requests.exceptions.RequestException as error:
500-
self._handle_http_error('Failed to download user accounts.', error)
500+
_auth_utils.handle_http_error('Failed to download user accounts.', error)
501501

502502
def create_user(self, uid=None, display_name=None, email=None, phone_number=None,
503503
photo_url=None, password=None, disabled=None, email_verified=None):
@@ -516,7 +516,7 @@ def create_user(self, uid=None, display_name=None, email=None, phone_number=None
516516
try:
517517
body, response = self._client.body_and_response('post', '/accounts', json=payload)
518518
except requests.exceptions.RequestException as error:
519-
self._handle_http_error('Failed to create new user.', error)
519+
_auth_utils.handle_http_error('Failed to create new user.', error)
520520
else:
521521
if not body or not body.get('localId'):
522522
raise _auth_utils.FirebaseAuthError(
@@ -570,7 +570,7 @@ def update_user(self, uid, display_name=_UNSPECIFIED, email=None, phone_number=_
570570
try:
571571
body, response = self._client.body_and_response('post', '/accounts:update', json=payload)
572572
except requests.exceptions.RequestException as error:
573-
self._handle_http_error('Failed to update user: {0}.'.format(uid), error)
573+
_auth_utils.handle_http_error('Failed to update user: {0}.'.format(uid), error)
574574
else:
575575
if not body or not body.get('localId'):
576576
raise _auth_utils.FirebaseAuthError(
@@ -586,7 +586,7 @@ def delete_user(self, uid):
586586
try:
587587
body, response = self._client.body_and_response('post', '/accounts:delete', json={'localId' : uid})
588588
except requests.exceptions.RequestException as error:
589-
self._handle_http_error('Failed to delete user: {0}.'.format(uid), error)
589+
_auth_utils.handle_http_error('Failed to delete user: {0}.'.format(uid), error)
590590
else:
591591
if not body or not body.get('kind'):
592592
raise _auth_utils.FirebaseAuthError(
@@ -615,7 +615,7 @@ def import_users(self, users, hash_alg=None):
615615
try:
616616
body, response = self._client.body_and_response('post', '/accounts:batchCreate', json=payload)
617617
except requests.exceptions.RequestException as error:
618-
self._handle_http_error('Failed to import users.', error)
618+
_auth_utils.handle_http_error('Failed to import users.', error)
619619
else:
620620
if not isinstance(body, dict):
621621
raise _auth_utils.FirebaseAuthError(
@@ -653,7 +653,7 @@ def generate_email_action_link(self, action_type, email, action_code_settings=No
653653
try:
654654
body, response = self._client.body_and_response('post', '/accounts:sendOobCode', json=payload)
655655
except requests.exceptions.RequestException as error:
656-
self._handle_http_error('Failed to generate link.', error)
656+
_auth_utils.handle_http_error('Failed to generate link.', error)
657657
else:
658658
if not body or not body.get('oobLink'):
659659
raise _auth_utils.FirebaseAuthError(
@@ -663,26 +663,6 @@ def generate_email_action_link(self, action_type, email, action_code_settings=No
663663
auth_error_code=UNEXPECTED_RESPONSE)
664664
return body.get('oobLink')
665665

666-
_ERROR_CODE_MAPPINGS = {
667-
'CLAIMS_TOO_LARGE': exceptions.INVALID_ARGUMENT,
668-
'INVALID_EMAIL': exceptions.INVALID_ARGUMENT,
669-
'INSUFFICIENT_PERMISSION': exceptions.PERMISSION_DENIED,
670-
'OPERATION_NOT_ALLOWED': exceptions.PERMISSION_DENIED,
671-
'PERMISSION_DENIED': exceptions.PERMISSION_DENIED,
672-
'USER_NOT_FOUND': exceptions.NOT_FOUND,
673-
'DUPLICATE_EMAIL': exceptions.ALREADY_EXISTS,
674-
}
675-
676-
def _handle_http_error(self, msg, error):
677-
response_payload = {}
678-
if error.response is not None:
679-
response_payload = error.response.json()
680-
msg += '\n Server response: {0}'.format(error.response.content.decode())
681-
server_code = response_payload.get('error', {}).get('message')
682-
canonical_code = self._ERROR_CODE_MAPPINGS.get(server_code, exceptions.UNKNOWN)
683-
raise _auth_utils.FirebaseAuthError(
684-
canonical_code, msg, cause=error, http_response=error.response, auth_error_code=server_code)
685-
686666

687667
class _UserIterator(object):
688668
"""An iterator that allows iterating over user accounts, one at a time.

firebase_admin/auth.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,7 @@ def create_custom_token(uid, developer_claims=None, app=None):
128128
AuthError: If an error occurs while creating the token using the remote IAM service.
129129
"""
130130
token_generator = _get_auth_service(app).token_generator
131-
try:
132-
return token_generator.create_custom_token(uid, developer_claims)
133-
except _token_gen.ApiCallError as error:
134-
raise FirebaseAuthError(error.code, str(error), cause=error)
131+
return token_generator.create_custom_token(uid, developer_claims)
135132

136133

137134
def verify_id_token(id_token, app=None, check_revoked=False):
@@ -183,10 +180,7 @@ def create_session_cookie(id_token, expires_in, app=None):
183180
AuthError: If an error occurs while creating the cookie.
184181
"""
185182
token_generator = _get_auth_service(app).token_generator
186-
try:
187-
return token_generator.create_session_cookie(id_token, expires_in)
188-
except _token_gen.ApiCallError as error:
189-
raise FirebaseAuthError(error.code, str(error), cause=error)
183+
return token_generator.create_session_cookie(id_token, expires_in)
190184

191185

192186
def verify_session_cookie(session_cookie, check_revoked=False, app=None):

tests/test_token_gen.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import time
2222

2323
from google.auth import crypt
24-
from google.auth import exceptions
2524
from google.auth import jwt
2625
import google.oauth2.id_token
2726
import pytest
@@ -31,6 +30,7 @@
3130
import firebase_admin
3231
from firebase_admin import auth
3332
from firebase_admin import credentials
33+
from firebase_admin import exceptions
3434
from firebase_admin import _token_gen
3535
from tests import testutils
3636

@@ -221,7 +221,8 @@ def test_sign_with_iam_error(self):
221221
_overwrite_iam_request(app, testutils.MockRequest(403, iam_resp))
222222
with pytest.raises(auth.FirebaseAuthError) as excinfo:
223223
auth.create_custom_token(MOCK_UID, app=app)
224-
assert excinfo.value.code == _token_gen.TOKEN_SIGN_ERROR
224+
assert excinfo.value.code == exceptions.UNKNOWN
225+
assert excinfo.value._auth_error_code == _token_gen.TOKEN_SIGN_FAILED
225226
assert iam_resp in str(excinfo.value)
226227
finally:
227228
firebase_admin.delete_app(app)
@@ -298,17 +299,18 @@ def test_valid_args(self, user_mgt_app, expires_in):
298299
assert request == {'idToken' : 'id_token', 'validDuration': 3600}
299300

300301
def test_error(self, user_mgt_app):
301-
_instrument_user_manager(user_mgt_app, 500, '{"error":"test"}')
302+
test_response = '{"error":{"message": "test"}}'
303+
_instrument_user_manager(user_mgt_app, 500, test_response)
302304
with pytest.raises(auth.FirebaseAuthError) as excinfo:
303305
auth.create_session_cookie('id_token', expires_in=3600, app=user_mgt_app)
304-
assert excinfo.value.code == _token_gen.COOKIE_CREATE_ERROR
305-
assert '{"error":"test"}' in str(excinfo.value)
306+
assert excinfo.value.code == exceptions.UNKNOWN
307+
assert test_response in str(excinfo.value)
306308

307309
def test_unexpected_response(self, user_mgt_app):
308310
_instrument_user_manager(user_mgt_app, 200, '{}')
309311
with pytest.raises(auth.FirebaseAuthError) as excinfo:
310312
auth.create_session_cookie('id_token', expires_in=3600, app=user_mgt_app)
311-
assert excinfo.value.code == _token_gen.COOKIE_CREATE_ERROR
313+
assert excinfo.value.code == exceptions.UNKNOWN
312314
assert 'Failed to create session cookie' in str(excinfo.value)
313315

314316

@@ -370,6 +372,7 @@ def test_revoked_token_check_revoked(self, user_mgt_app, revoked_tokens, id_toke
370372
_instrument_user_manager(user_mgt_app, 200, revoked_tokens)
371373
with pytest.raises(auth.FirebaseAuthError) as excinfo:
372374
auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=True)
375+
assert excinfo.value.code == exceptions.INVALID_ARGUMENT
373376
assert excinfo.value.auth_error_code == 'ID_TOKEN_REVOKED'
374377
assert str(excinfo.value) == 'The Firebase ID token has been revoked.'
375378

@@ -421,8 +424,10 @@ def test_custom_token(self, auth_app):
421424

422425
def test_certificate_request_failure(self, user_mgt_app):
423426
_overwrite_cert_request(user_mgt_app, testutils.MockRequest(404, 'not found'))
424-
with pytest.raises(exceptions.TransportError):
427+
with pytest.raises(auth.FirebaseAuthError) as excinfo:
425428
auth.verify_id_token(TEST_ID_TOKEN, app=user_mgt_app)
429+
assert excinfo.value.code == exceptions.UNKNOWN
430+
assert excinfo.value.auth_error_code == 'CERTIFICATE_FETCH_FAILED'
426431

427432

428433
class TestVerifySessionCookie(object):
@@ -479,6 +484,7 @@ def test_revoked_cookie_check_revoked(self, user_mgt_app, revoked_tokens, cookie
479484
_instrument_user_manager(user_mgt_app, 200, revoked_tokens)
480485
with pytest.raises(auth.FirebaseAuthError) as excinfo:
481486
auth.verify_session_cookie(cookie, app=user_mgt_app, check_revoked=True)
487+
assert excinfo.value.code == exceptions.INVALID_ARGUMENT
482488
assert excinfo.value.auth_error_code == 'SESSION_COOKIE_REVOKED'
483489
assert str(excinfo.value) == 'The Firebase session cookie has been revoked.'
484490

@@ -521,8 +527,10 @@ def test_custom_token(self, auth_app):
521527

522528
def test_certificate_request_failure(self, user_mgt_app):
523529
_overwrite_cert_request(user_mgt_app, testutils.MockRequest(404, 'not found'))
524-
with pytest.raises(exceptions.TransportError):
530+
with pytest.raises(auth.FirebaseAuthError) as excinfo:
525531
auth.verify_session_cookie(TEST_SESSION_COOKIE, app=user_mgt_app)
532+
assert excinfo.value.code == exceptions.UNKNOWN
533+
assert excinfo.value.auth_error_code == 'CERTIFICATE_FETCH_FAILED'
526534

527535

528536
class TestCertificateCaching(object):

0 com 30A6 mit comments

Comments
 (0)
0