Skip to content

Commit af6214e

Browse files
committed
[fix] Support phone numbers with leading zero in auth backend
This fix allows users of countries which use leading zeros in their national phone numbers to authenticate successfully by using the version of their number with the leading zero, which without this patch fails to be recognized.
1 parent 8a39e48 commit af6214e

File tree

3 files changed

+44
-37
lines changed

3 files changed

+44
-37
lines changed

README.rst

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ Create User
606606
607607
POST /api/v1/users/user/
608608
609-
**Note**: Passing ``true`` to the optional
609+
**Note**: Passing ``true`` to the optional
610610
``is_verified`` field allows creating users with
611611
their email address flagged as verified. This will
612612
also skip sending the verification link to their
@@ -803,27 +803,30 @@ Usage example:
803803
Authentication Backend
804804
----------------------
805805

806-
The authentication backend in ``openwisp_users.backends.UsersAuthenticationBackend``
807-
allows users to authenticate using their
808-
``email`` or ``phone_number`` instead of their ``username``.
809-
Authenticating with the ``username`` is still allowed,
810-
but ``email`` has precedence.
806+
The authentication backend in
807+
``openwisp_users.backends.UsersAuthenticationBackend``
808+
allows users to authenticate using their ``email`` or ``phone_number``
809+
instead of their ``username``. Authenticating with the ``username`` is
810+
still supported, but ``email`` takes precedence.
811811

812-
If the username string passed is parsed as a valid phone number, then
813-
``phone_number`` has precedence.
812+
If the provided username string is parsed as a valid phone number, then
813+
``phone_number`` takes precedence.
814814

815-
Phone numbers are parsed using the ``phonenumbers`` library, which means
816-
that even if the user adds characters like spaces, dots or dashes, the number
817-
will be recognized anyway.
815+
Phone numbers are parsed using the
816+
`phonenumbers <https://github.com/daviddrysdale/python-phonenumbers>`_
817+
library, which ensures that numbers are recognized even if users
818+
include characters like spaces, dots, or dashes.
818819

819-
When parsing phone numbers, the
820-
`OPENWISP_USERS_AUTH_BACKEND_AUTO_PREFIXES
821-
<#openwisp_users_auth_backend_auto_prefixes>`_
822-
setting allows to specify a list of international prefixes that can
823-
be prepended to the username string automatically in order to allow
824-
users to log in without having to type the international prefix.
820+
The ``OPENWISP_USERS_AUTH_BACKEND_AUTO_PREFIXES`` setting allows specifying
821+
a list of international prefixes that can be automatically prepended to the
822+
username string, enabling users to log in without typing the international
823+
prefix.
825824

826-
The authentication backend can also be used as follows:
825+
Additionally, the backend supports phone numbers with a leading zero, which
826+
is common in some countries for local numbers. This ensures users can
827+
authenticate successfully even if they include the leading zero.
828+
829+
The authentication backend can also be used programmatically, for example:
827830

828831
.. code-block:: python
829832

openwisp_users/backends.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@
1111

1212
class UsersAuthenticationBackend(ModelBackend):
1313
def authenticate(self, request, username=None, password=None, **kwargs):
14-
queryset = self.get_users(username)
15-
try:
16-
# can not use queryset.first() because it orders the queryset
17-
# by pk before returning the first object which is not what we want
18-
user = queryset[0]
19-
except IndexError:
20-
return None
21-
if user.check_password(password) and self.user_can_authenticate(user):
22-
return user
14+
for user in self.get_users(username):
15+
if user.check_password(password) and self.user_can_authenticate(user):
16+
return user
2317

2418
def get_users(self, identifier):
2519
conditions = Q(email=identifier) | Q(username=identifier)
2620
# if the identifier is a phone number, use the phone number as primary condition
27-
phone_number = self._get_phone_number(identifier)
28-
if phone_number:
21+
for phone_number in self._get_phone_numbers(identifier):
2922
conditions = Q(phone_number=phone_number) | conditions
3023
return User.objects.filter(conditions)
3124

32-
def _get_phone_number(self, identifier):
25+
def _get_phone_numbers(self, identifier):
3326
prefixes = [''] + list(app_settings.AUTH_BACKEND_AUTO_PREFIXES)
27+
numbers = [identifier]
28+
found = []
29+
# support those countries which use
30+
# leading zeros for their local numbers
31+
if str(identifier).startswith('0'):
32+
numbers.append(identifier[1:])
3433
for prefix in prefixes:
35-
value = f'{prefix}{identifier}'
36-
try:
37-
phonenumbers.parse(value)
38-
return value
39-
except NumberParseException:
40-
pass
41-
return False
34+
for number in numbers:
35+
value = f'{prefix}{number}'
36+
try:
37+
phonenumbers.parse(value)
38+
found.append(value)
39+
except NumberParseException:
40+
continue
41+
return found

openwisp_users/tests/test_backends.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ def test_partial_phone_number(self):
141141
self.assertEqual(auth_backend.get_users('3665243702').count(), 1)
142142
self.assertEqual(auth_backend.get_users('3665243702').first(), user1)
143143

144+
with self.subTest('test with leading zero'):
145+
self.assertEqual(auth_backend.get_users('03665243702').count(), 1)
146+
self.assertEqual(auth_backend.get_users('03665243702').first(), user1)
147+
144148
with self.subTest('test different prefix which is not enabled'):
145149
self._create_user(
146150
username='tester2',

0 commit comments

Comments
 (0)