From 35db6530332738ddccf015931357ce8b3817b7d6 Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 15 Jul 2021 15:44:51 +0100 Subject: [PATCH 01/12] feat: added firebase_user.phone_number for mapping email field as an identifier --- drf_firebase_auth/utils.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drf_firebase_auth/utils.py b/drf_firebase_auth/utils.py index fc44418..e13a4b7 100644 --- a/drf_firebase_auth/utils.py +++ b/drf_firebase_auth/utils.py @@ -7,11 +7,12 @@ def get_firebase_user_email(firebase_user: auth.UserRecord) -> str: try: - return ( - firebase_user.email - if firebase_user.email - else firebase_user.provider_data[0].email - ) + if firebase_user.email: + return firebase_user.email + elif firebase_user.phone_number: + return firebase_user.phone_number + else: + firebase_user.provider_data[0].email except Exception as e: raise Exception(e) From 4051d253ec29c380974df170494509e8abc20bf2 Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Fri, 16 Jul 2021 10:00:23 +0100 Subject: [PATCH 02/12] fix: changed function name, added more alternative to map --- drf_firebase_auth/authentication.py | 4 ++-- drf_firebase_auth/utils.py | 10 +++++++--- testapp/api/tests.py | 22 +++++++++++----------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/drf_firebase_auth/authentication.py b/drf_firebase_auth/authentication.py index a108244..db371ab 100755 --- a/drf_firebase_auth/authentication.py +++ b/drf_firebase_auth/authentication.py @@ -22,7 +22,7 @@ FirebaseUser, FirebaseUserProvider ) -from .utils import get_firebase_user_email +from .utils import get_firebase_user_identifier from . import __title__ log = logging.getLogger(__title__) @@ -98,7 +98,7 @@ def _get_or_create_local_user( """ Attempts to return or create a local User from Firebase user data """ - email = get_firebase_user_email(firebase_user) + email = get_firebase_user_identifier(firebase_user) log.info(f'_get_or_create_local_user - email: {email}') user = None try: diff --git a/drf_firebase_auth/utils.py b/drf_firebase_auth/utils.py index e13a4b7..5279bed 100644 --- a/drf_firebase_auth/utils.py +++ b/drf_firebase_auth/utils.py @@ -5,14 +5,18 @@ from firebase_admin import auth -def get_firebase_user_email(firebase_user: auth.UserRecord) -> str: +def get_firebase_user_identifier(firebase_user: auth.UserRecord) -> str: try: if firebase_user.email: return firebase_user.email + elif firebase_user.provider_data[0].email: + firebase_user.provider_data[0].email elif firebase_user.phone_number: return firebase_user.phone_number + elif firebase_user.provider_data[0].phone_number: + return firebase_user.provider_data[0].phone_number else: - firebase_user.provider_data[0].email + raise Exception("Identifier not found, this would fail authentication process") except Exception as e: raise Exception(e) @@ -51,7 +55,7 @@ def map_firebase_email_to_username( firebase_user: auth.UserRecord ) -> str: try: - return get_firebase_user_email(firebase_user) + return get_firebase_user_identifier(firebase_user) except Exception as e: raise Exception(e) diff --git a/testapp/api/tests.py b/testapp/api/tests.py index ff56dc9..442a47d 100644 --- a/testapp/api/tests.py +++ b/testapp/api/tests.py @@ -10,7 +10,7 @@ from firebase_admin import auth as firebase_auth from drf_firebase_auth.settings import api_settings from drf_firebase_auth.utils import ( - get_firebase_user_email, + get_firebase_user_identifier, map_firebase_uid_to_username, map_firebase_email_to_username ) @@ -25,7 +25,7 @@ ) class WhoAmITests(APITestCase): - + def setUp(self): self._url = reverse('whoami') self._test_user_email = 'user@example.com' @@ -103,7 +103,7 @@ def test_authenticated_request(self): status.HTTP_403_FORBIDDEN, f'{api_settings.FIREBASE_CREATE_LOCAL_USER}' ) - + with self._MOCK_FIREBASE_CREATE_LOCAL_USER_TRUE: response = self.client.get(self._url) self.assertEqual( @@ -143,11 +143,11 @@ def test_user_creation_uid_as_username(self): ) ) firebase_user = self._get_test_user() - firebase_user_email = get_firebase_user_email(firebase_user) + firebase_user_email = get_firebase_user_identifier(firebase_user) with self._MOCK_FIREBASE_CREATE_LOCAL_USER_FALSE: before_count = User.objects.count() - + response = self.client.get(self._url) self.assertEqual( response.status_code, @@ -161,11 +161,11 @@ def test_user_creation_uid_as_username(self): with self.assertRaises(Exception): _ = User.objects.get(email=firebase_user_email) - + with self._MOCK_FIREBASE_CREATE_LOCAL_USER_TRUE: with self._MOCK_FIREBASE_USERNAME_MAPPING_FUNC_UID: before_count = User.objects.count() - + response = self.client.get(self._url) self.assertEqual( response.status_code, @@ -193,11 +193,11 @@ def test_user_creation_email_as_username(self): ) ) firebase_user = self._get_test_user() - firebase_user_email = get_firebase_user_email(firebase_user) + firebase_user_email = get_firebase_user_identifier(firebase_user) with self._MOCK_FIREBASE_CREATE_LOCAL_USER_FALSE: before_count = User.objects.count() - + response = self.client.get(self._url) self.assertEqual( response.status_code, @@ -211,11 +211,11 @@ def test_user_creation_email_as_username(self): with self.assertRaises(Exception): _ = User.objects.get(email=firebase_user_email) - + with self._MOCK_FIREBASE_CREATE_LOCAL_USER_TRUE: with self._MOCK_FIREBASE_USERNAME_MAPPING_FUNC_EMAIL: before_count = User.objects.count() - + response = self.client.get(self._url) self.assertEqual( response.status_code, From 151d83eb112f1b42ad46cfbf4421c37312be0f01 Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Sat, 17 Jul 2021 17:47:01 +0100 Subject: [PATCH 03/12] fix: added provider email --- drf_firebase_auth/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drf_firebase_auth/utils.py b/drf_firebase_auth/utils.py index 5279bed..fad2224 100644 --- a/drf_firebase_auth/utils.py +++ b/drf_firebase_auth/utils.py @@ -10,7 +10,7 @@ def get_firebase_user_identifier(firebase_user: auth.UserRecord) -> str: if firebase_user.email: return firebase_user.email elif firebase_user.provider_data[0].email: - firebase_user.provider_data[0].email + return firebase_user.provider_data[0].email elif firebase_user.phone_number: return firebase_user.phone_number elif firebase_user.provider_data[0].phone_number: From b5b013a1cea38cec216946183e273e341b536a30 Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 22 Jul 2021 09:45:35 +0100 Subject: [PATCH 04/12] fix: changed function name according with new feature --- drf_firebase_auth/authentication.py | 4 ++-- drf_firebase_auth/utils.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drf_firebase_auth/authentication.py b/drf_firebase_auth/authentication.py index db371ab..64748b4 100755 --- a/drf_firebase_auth/authentication.py +++ b/drf_firebase_auth/authentication.py @@ -22,7 +22,7 @@ FirebaseUser, FirebaseUserProvider ) -from .utils import get_firebase_user_identifier +from .utils import get_firebase_user_uid from . import __title__ log = logging.getLogger(__title__) @@ -98,7 +98,7 @@ def _get_or_create_local_user( """ Attempts to return or create a local User from Firebase user data """ - email = get_firebase_user_identifier(firebase_user) + email = get_firebase_user_uid(firebase_user) log.info(f'_get_or_create_local_user - email: {email}') user = None try: diff --git a/drf_firebase_auth/utils.py b/drf_firebase_auth/utils.py index fad2224..2a9ed9c 100644 --- a/drf_firebase_auth/utils.py +++ b/drf_firebase_auth/utils.py @@ -5,7 +5,7 @@ from firebase_admin import auth -def get_firebase_user_identifier(firebase_user: auth.UserRecord) -> str: +def get_firebase_user_uid(firebase_user: auth.UserRecord) -> str: try: if firebase_user.email: return firebase_user.email @@ -55,7 +55,7 @@ def map_firebase_email_to_username( firebase_user: auth.UserRecord ) -> str: try: - return get_firebase_user_identifier(firebase_user) + return get_firebase_user_uid(firebase_user) except Exception as e: raise Exception(e) From 7725f980cc2bb47869b43b4bbbfe44b4aa2f51cb Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 22 Jul 2021 09:53:43 +0100 Subject: [PATCH 05/12] feat: created function get_firebase_user_uid in utils.py --- drf_firebase_auth/utils.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drf_firebase_auth/utils.py b/drf_firebase_auth/utils.py index 2a9ed9c..e66afe5 100644 --- a/drf_firebase_auth/utils.py +++ b/drf_firebase_auth/utils.py @@ -6,6 +6,14 @@ def get_firebase_user_uid(firebase_user: auth.UserRecord) -> str: + try: + if firebase_user.uid: + return firebase_user.uid + except Exception as e: + raise Exception(e) + + +def get_firebase_user_identifier(firebase_user: auth.UserRecord) -> str: try: if firebase_user.email: return firebase_user.email @@ -55,7 +63,7 @@ def map_firebase_email_to_username( firebase_user: auth.UserRecord ) -> str: try: - return get_firebase_user_uid(firebase_user) + return get_firebase_user_identifier(firebase_user) except Exception as e: raise Exception(e) From 4d2363b632f900b954139bcd15b9053003af165d Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 22 Jul 2021 09:54:42 +0100 Subject: [PATCH 06/12] feat: changed user get and create to rely on uid instead of email or identifier --- drf_firebase_auth/authentication.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drf_firebase_auth/authentication.py b/drf_firebase_auth/authentication.py index 64748b4..ad1c00f 100755 --- a/drf_firebase_auth/authentication.py +++ b/drf_firebase_auth/authentication.py @@ -22,7 +22,7 @@ FirebaseUser, FirebaseUserProvider ) -from .utils import get_firebase_user_uid +from .utils import get_firebase_user_uid, get_firebase_user_identifier from . import __title__ log = logging.getLogger(__title__) @@ -98,11 +98,12 @@ def _get_or_create_local_user( """ Attempts to return or create a local User from Firebase user data """ - email = get_firebase_user_uid(firebase_user) - log.info(f'_get_or_create_local_user - email: {email}') + uid = get_firebase_user_uid(firebase_user) + identifer = get_firebase_user_identifier(firebase_user) + log.info(f'_get_or_create_local_user - email: {identifer}') user = None try: - user = User.objects.get(email=email) + user = User.objects.get(username=uid) log.info( f'_get_or_create_local_user - user.is_active: {user.is_active}' ) @@ -114,19 +115,19 @@ def _get_or_create_local_user( user.save() except User.DoesNotExist as e: log.error( - f'_get_or_create_local_user - User.DoesNotExist: {email}' + f'_get_or_create_local_user - User.DoesNotExist: {identifier}' ) if not api_settings.FIREBASE_CREATE_LOCAL_USER: raise Exception('User is not registered to the application.') username = \ api_settings.FIREBASE_USERNAME_MAPPING_FUNC(firebase_user) log.info( - f'_get_or_create_local_user - username: {username}' + f'_get_or_create_local_user - username: {uid}' ) try: user = User.objects.create_user( - username=username, - email=email + username=uid, + email=identifier ) user.last_login = timezone.now() if ( From df9161996011de81eb68d6aaf7ca5589cc93db1d Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 22 Jul 2021 10:48:48 +0100 Subject: [PATCH 07/12] feat: added debugging messsages --- drf_firebase_auth/authentication.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drf_firebase_auth/authentication.py b/drf_firebase_auth/authentication.py index ad1c00f..9612a6f 100755 --- a/drf_firebase_auth/authentication.py +++ b/drf_firebase_auth/authentication.py @@ -99,6 +99,7 @@ def _get_or_create_local_user( Attempts to return or create a local User from Firebase user data """ uid = get_firebase_user_uid(firebase_user) + print(f"drf-firebase-auth: uid is {uid}") identifer = get_firebase_user_identifier(firebase_user) log.info(f'_get_or_create_local_user - email: {identifer}') user = None @@ -114,6 +115,7 @@ def _get_or_create_local_user( user.last_login = timezone.now() user.save() except User.DoesNotExist as e: + print("drf-firebase-auth: User.DoesNotExist exception was raised.") log.error( f'_get_or_create_local_user - User.DoesNotExist: {identifier}' ) @@ -140,6 +142,8 @@ def _get_or_create_local_user( user.last_name = display_name[1] user.save() except Exception as e: + print("drf-firebase-auth: Unable to create new user.") + print(f"drf-firebase-auth: The following exception occurred {e}") raise Exception(e) return user From 9094dcd8bd4d887b0ef8f8916c9fb012bcb1d864 Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 22 Jul 2021 10:54:16 +0100 Subject: [PATCH 08/12] fix: added debug line --- drf_firebase_auth/authentication.py | 1 + 1 file changed, 1 insertion(+) diff --git a/drf_firebase_auth/authentication.py b/drf_firebase_auth/authentication.py index 9612a6f..9cd9349 100755 --- a/drf_firebase_auth/authentication.py +++ b/drf_firebase_auth/authentication.py @@ -141,6 +141,7 @@ def _get_or_create_local_user( user.first_name = display_name[0] user.last_name = display_name[1] user.save() + print("drf-firebase-auth: New user was created succesufully.") except Exception as e: print("drf-firebase-auth: Unable to create new user.") print(f"drf-firebase-auth: The following exception occurred {e}") From 52278c50221b3424c2b4bd055d8e2a29b91d44ce Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 22 Jul 2021 11:08:52 +0100 Subject: [PATCH 09/12] fix: added debug --- drf_firebase_auth/authentication.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drf_firebase_auth/authentication.py b/drf_firebase_auth/authentication.py index 9cd9349..150d85e 100755 --- a/drf_firebase_auth/authentication.py +++ b/drf_firebase_auth/authentication.py @@ -127,10 +127,12 @@ def _get_or_create_local_user( f'_get_or_create_local_user - username: {uid}' ) try: + print("drf-firebase-auth: Starting to create user...") user = User.objects.create_user( username=uid, email=identifier ) + print("drf-firebase-auth: New user was created succesufully.") user.last_login = timezone.now() if ( api_settings.FIREBASE_ATTEMPT_CREATE_WITH_DISPLAY_NAME @@ -141,7 +143,7 @@ def _get_or_create_local_user( user.first_name = display_name[0] user.last_name = display_name[1] user.save() - print("drf-firebase-auth: New user was created succesufully.") + print("drf-firebase-auth: New user was saved succesufully.") except Exception as e: print("drf-firebase-auth: Unable to create new user.") print(f"drf-firebase-auth: The following exception occurred {e}") From 1082443c88509c88d7d5f8dd376cfcddce6d9551 Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Thu, 22 Jul 2021 11:20:20 +0100 Subject: [PATCH 10/12] fix: fixed variable name and conducted successful tests for the app --- drf_firebase_auth/authentication.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drf_firebase_auth/authentication.py b/drf_firebase_auth/authentication.py index 150d85e..e9b72cd 100755 --- a/drf_firebase_auth/authentication.py +++ b/drf_firebase_auth/authentication.py @@ -99,9 +99,8 @@ def _get_or_create_local_user( Attempts to return or create a local User from Firebase user data """ uid = get_firebase_user_uid(firebase_user) - print(f"drf-firebase-auth: uid is {uid}") - identifer = get_firebase_user_identifier(firebase_user) - log.info(f'_get_or_create_local_user - email: {identifer}') + identifier = get_firebase_user_identifier(firebase_user) + log.info(f'_get_or_create_local_user - email: {identifier}') user = None try: user = User.objects.get(username=uid) @@ -115,7 +114,6 @@ def _get_or_create_local_user( user.last_login = timezone.now() user.save() except User.DoesNotExist as e: - print("drf-firebase-auth: User.DoesNotExist exception was raised.") log.error( f'_get_or_create_local_user - User.DoesNotExist: {identifier}' ) @@ -127,12 +125,10 @@ def _get_or_create_local_user( f'_get_or_create_local_user - username: {uid}' ) try: - print("drf-firebase-auth: Starting to create user...") user = User.objects.create_user( username=uid, email=identifier ) - print("drf-firebase-auth: New user was created succesufully.") user.last_login = timezone.now() if ( api_settings.FIREBASE_ATTEMPT_CREATE_WITH_DISPLAY_NAME @@ -143,10 +139,7 @@ def _get_or_create_local_user( user.first_name = display_name[0] user.last_name = display_name[1] user.save() - print("drf-firebase-auth: New user was saved succesufully.") except Exception as e: - print("drf-firebase-auth: Unable to create new user.") - print(f"drf-firebase-auth: The following exception occurred {e}") raise Exception(e) return user From edbfee75e81c7515bf43033f154433034a0de8f2 Mon Sep 17 00:00:00 2001 From: Ahmane Samir Date: Fri, 23 Jul 2021 14:54:57 +0100 Subject: [PATCH 11/12] feat: removed unnecessary mapping functions for the username field --- drf_firebase_auth/utils.py | 39 -------------------------------------- 1 file changed, 39 deletions(-) diff --git a/drf_firebase_auth/utils.py b/drf_firebase_auth/utils.py index e66afe5..96b45a0 100644 --- a/drf_firebase_auth/utils.py +++ b/drf_firebase_auth/utils.py @@ -29,27 +29,6 @@ def get_firebase_user_identifier(firebase_user: auth.UserRecord) -> str: raise Exception(e) -def map_firebase_to_username_legacy(firebase_user: auth.UserRecord) -> str: - try: - username = '_'.join( - firebase_user.display_name.split(' ') - if firebase_user.display_name - else str(uuid.uuid4()) - ) - return username if len(username) <= 30 else username[:30] - except Exception as e: - raise Exception(e) - - -def map_firebase_display_name_to_username( - firebase_user: auth.UserRecord -) -> str: - try: - return '_'.join(firebase_user.display_name.split(' ')) - except Exception as e: - raise Exception(e) - - def map_firebase_uid_to_username( firebase_user: auth.UserRecord ) -> str: @@ -57,21 +36,3 @@ def map_firebase_uid_to_username( return firebase_user.uid except Exception as e: raise Exception(e) - - -def map_firebase_email_to_username( - firebase_user: auth.UserRecord -) -> str: - try: - return get_firebase_user_identifier(firebase_user) - except Exception as e: - raise Exception(e) - - -def map_uuid_to_username( - _: auth.UserRecord -) -> str: - try: - return str(uuid.uuid4()) - except Exception as e: - raise Exception(e) From b7f0e42a178076812120a2ee8923c5c3109419ca Mon Sep 17 00:00:00 2001 From: Samir Ahmane <55358999+Arka-cell@users.noreply.github.com> Date: Fri, 23 Jul 2021 15:08:31 +0100 Subject: [PATCH 12/12] fix: removed unnecessary settings documentation --- README.md | 56 ------------------------------------------------------- 1 file changed, 56 deletions(-) diff --git a/README.md b/README.md index 5573ea7..0aa14de 100755 --- a/README.md +++ b/README.md @@ -65,67 +65,11 @@ DRF_FIREBASE_AUTH = { # require that firebase user.email_verified is True 'FIREBASE_AUTH_EMAIL_VERIFICATION': os.getenv('FIREBASE_AUTH_EMAIL_VERIFICATION', False), - # function should accept firebase_admin.auth.UserRecord as argument - # and return str - 'FIREBASE_USERNAME_MAPPING_FUNC': map_firebase_uid_to_username } ``` You can get away with leaving all the settings as default except for `FIREBASE_SERVICE_ACCOUNT_KEY`, which is obviously required. -NOTE: `FIREBASE_USERNAME_MAPPING_FUNC` will replace behaviour in version < 1 as default (formerly provided by logic in `map_firebase_to_username_legacy`, described below). One can simply switch out this function. - -`drf_firebase_auth.utils` contains functions for mapping firebase user info to the Django username field (new in version >= 1). Any custom function can be supplied here, as long as it accepts a `firebase_admin.auth.UserRecord` argument. The supplied functions are common use-cases: - -```python -def map_firebase_to_username_legacy(firebase_user: auth.UserRecord) -> str: - try: - username = '_'.join( - firebase_user.display_name.split(' ') - if firebase_user.display_name - else str(uuid.uuid4()) - ) - return username if len(username) <= 30 else username[:30] - except Exception as e: - raise Exception(e) - - -def map_firebase_display_name_to_username( - firebase_user: auth.UserRecord -) -> str: - try: - return '_'.join(firebase_user.display_name.split(' ')) - except Exception as e: - raise Exception(e) - - -def map_firebase_uid_to_username( - firebase_user: auth.UserRecord -) -> str: - try: - return firebase_user.uid - except Exception as e: - raise Exception(e) - - -def map_firebase_email_to_username( - firebase_user: auth.UserRecord -) -> str: - try: - return get_firebase_user_email(firebase_user) - except Exception as e: - raise Exception(e) - - -def map_uuid_to_username( - _: auth.UserRecord -) -> str: - try: - return str(uuid.uuid4()) - except Exception as e: - raise Exception(e) -``` - Now that you have configured the application, run the migrations so that the Firebase data can be stored. ```