mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Resolve the log in issue for a user having a non-existing email id
1) Added CHECK_EMAIL_DELIVERABILITY & SECURITY_EMAIL_VALIDATOR_ARGS. 2) Added test cases for deliverability check. Fixes #6550
This commit is contained in:
parent
ef67409d61
commit
9fdda038a9
@ -388,7 +388,9 @@ SECURITY_EMAIL_SUBJECT_PASSWORD_CHANGE_NOTICE = \
|
||||
# flask-security-too will validate email addresses and check deliverability
|
||||
# by default. Disable the deliverability check by default, which was the old
|
||||
# behaviour in <= v5.3
|
||||
SECURITY_EMAIL_VALIDATOR_ARGS = {"check_deliverability": False}
|
||||
CHECK_EMAIL_DELIVERABILITY = False
|
||||
SECURITY_EMAIL_VALIDATOR_ARGS = \
|
||||
{"check_deliverability": CHECK_EMAIL_DELIVERABILITY}
|
||||
|
||||
##########################################################################
|
||||
# Upgrade checks
|
||||
|
@ -465,6 +465,8 @@ def create_app(app_name=None):
|
||||
# CSRF Token expiration till session expires
|
||||
'WTF_CSRF_TIME_LIMIT': getattr(config, 'CSRF_TIME_LIMIT', None),
|
||||
'WTF_CSRF_METHODS': ['GET', 'POST', 'PUT', 'DELETE'],
|
||||
# Disable deliverable check for email addresss
|
||||
'SECURITY_EMAIL_VALIDATOR_ARGS': config.SECURITY_EMAIL_VALIDATOR_ARGS
|
||||
}))
|
||||
|
||||
security.init_app(app, user_datastore)
|
||||
|
62
web/pgadmin/setup/tests/test_no_email_deliverability.py
Normal file
62
web/pgadmin/setup/tests/test_no_email_deliverability.py
Normal file
@ -0,0 +1,62 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from pgadmin.setup import user_info
|
||||
import config
|
||||
from regression.python_test_utils.test_utils import module_patch
|
||||
from unittest.mock import patch
|
||||
from pgadmin.utils.constants import ENTER_EMAIL_ADDRESS
|
||||
|
||||
|
||||
class EmailValidationOnSetup(BaseTestGenerator):
|
||||
"""
|
||||
This class tests the non-deliverability of email for invalid email id.
|
||||
This test case is only responsible for testing non-deliverability emails
|
||||
only.
|
||||
"""
|
||||
PPROMPT_RETURN_VALUE = '1234567'
|
||||
|
||||
scenarios = [
|
||||
# scenario for testing invalid email for non-deliverability only
|
||||
('TestCase for email validation', dict(
|
||||
data=['postgres@local.dev', 'pg@pgadminrocks.com',
|
||||
'me.pg@demo.dev', 'pg@123.pgcom',
|
||||
'pg@postgres.local', 'postgres@pg.blah'],
|
||||
check_deliverability=False,
|
||||
)),
|
||||
]
|
||||
|
||||
@patch('builtins.input')
|
||||
@patch('os.environ')
|
||||
def runTest(self, os_environ_mock, input_mock):
|
||||
|
||||
if config.SERVER_MODE is False:
|
||||
self.skipTest(
|
||||
"Can not email validation test cases in the DESKTOP mode."
|
||||
)
|
||||
|
||||
os_environ_mock.return_value = []
|
||||
config.CHECK_EMAIL_DELIVERABILITY = self.check_deliverability
|
||||
|
||||
with module_patch('pgadmin.setup.user_info.pprompt') as pprompt_mock:
|
||||
pprompt_mock.return_value \
|
||||
= self.PPROMPT_RETURN_VALUE, self.PPROMPT_RETURN_VALUE
|
||||
|
||||
for e in self.data:
|
||||
input_mock.return_value = e
|
||||
# skipping some setup-db part as we are only testing the
|
||||
# mail validation through setup.
|
||||
email, password = user_info()
|
||||
|
||||
input_mock.assert_called_once_with(ENTER_EMAIL_ADDRESS)
|
||||
# assert equal means deliverability is not done, and entered
|
||||
# email id is returned as it is.
|
||||
self.assertEqual(e, email)
|
||||
input_mock.reset_mock()
|
@ -13,6 +13,7 @@ import random
|
||||
import os
|
||||
import re
|
||||
import getpass
|
||||
from pgadmin.utils.constants import ENTER_EMAIL_ADDRESS
|
||||
|
||||
from pgadmin.utils.validation_utils import validate_email
|
||||
|
||||
@ -27,6 +28,10 @@ def user_info_desktop():
|
||||
return email, p1
|
||||
|
||||
|
||||
def pprompt():
|
||||
return getpass.getpass(), getpass.getpass('Retype password:')
|
||||
|
||||
|
||||
def user_info_server():
|
||||
print("NOTE: Configuring authentication for SERVER mode.\n")
|
||||
|
||||
@ -45,13 +50,10 @@ def user_info_server():
|
||||
"pgAdmin user account:\n"
|
||||
)
|
||||
|
||||
email = input("Email address: ")
|
||||
email = input(ENTER_EMAIL_ADDRESS)
|
||||
while not validate_email(email):
|
||||
print('Invalid email address. Please try again.')
|
||||
email = input("Email address: ")
|
||||
|
||||
def pprompt():
|
||||
return getpass.getpass(), getpass.getpass('Retype password:')
|
||||
email = input(ENTER_EMAIL_ADDRESS)
|
||||
|
||||
p1, p2 = pprompt()
|
||||
while p1 != p2 or len(p1) < 6:
|
||||
|
0
web/pgadmin/tools/user_management/tests/__init__.py
Normal file
0
web/pgadmin/tools/user_management/tests/__init__.py
Normal file
@ -0,0 +1,62 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from pgadmin.tools.user_management import validate_user
|
||||
from unittest.mock import patch
|
||||
import config
|
||||
|
||||
|
||||
class TestValidateUser(BaseTestGenerator):
|
||||
""" This class will test the user email validation with/without email
|
||||
deliverability while validating user. """
|
||||
|
||||
scenarios = [
|
||||
('User email validation (no deliverability)',
|
||||
dict(
|
||||
data=dict(
|
||||
email='postgres@local.dev',
|
||||
check_deliverability=False,
|
||||
expected_data=dict(
|
||||
test_result='postgres@local.dev'
|
||||
)
|
||||
)
|
||||
)),
|
||||
('User email validation (with deliverability)',
|
||||
dict(
|
||||
data=dict(
|
||||
email='postgres@local.dev',
|
||||
check_deliverability=True,
|
||||
expected_data=dict(
|
||||
test_result='Invalid email address.'
|
||||
)
|
||||
)
|
||||
))
|
||||
]
|
||||
|
||||
@patch('pgadmin.tools.user_management.validate_password')
|
||||
def runTest(self, validate_password_mock):
|
||||
|
||||
if config.SERVER_MODE is False:
|
||||
self.skipTest(
|
||||
"Can not email validation test cases in the DESKTOP mode."
|
||||
)
|
||||
config.CHECK_EMAIL_DELIVERABILITY = self.data['check_deliverability']
|
||||
ndata = {}
|
||||
|
||||
validate_password_mock.return_value.method.return_value = ''
|
||||
try:
|
||||
ndata = validate_user(self.data)
|
||||
except Exception as e:
|
||||
ndata['email'] = str(e.description)
|
||||
|
||||
# assert equal means deliverability is not done, and entered
|
||||
# email id is returned as it is.
|
||||
self.assertEqual(ndata['email'],
|
||||
self.data['expected_data']['test_result'])
|
@ -98,3 +98,5 @@ BINARY_PATHS = {
|
||||
}
|
||||
|
||||
UTILITIES_ARRAY = ['pg_dump', 'pg_dumpall', 'pg_restore', 'psql']
|
||||
|
||||
ENTER_EMAIL_ADDRESS = "Email address: "
|
||||
|
82
web/pgadmin/utils/tests/test_validate_email.py
Normal file
82
web/pgadmin/utils/tests/test_validate_email.py
Normal file
@ -0,0 +1,82 @@
|
||||
##########################################################################
|
||||
#
|
||||
# pgAdmin 4 - PostgreSQL Tools
|
||||
#
|
||||
# Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
# This software is released under the PostgreSQL Licence
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
from pgadmin.utils.route import BaseTestGenerator
|
||||
from pgadmin.utils.validation_utils import validate_email
|
||||
from unittest.mock import patch
|
||||
import config
|
||||
|
||||
|
||||
class TestEmailValidate(BaseTestGenerator):
|
||||
""" This class will test the email validation utility with or without email
|
||||
deliverability. """
|
||||
|
||||
scenarios = [
|
||||
('Email validation (no deliverability)',
|
||||
dict(
|
||||
data=dict(
|
||||
email_list=['postgres@local.dev', 'pg@pgadminrocks.com',
|
||||
'me.pg@demo.dev', 'pg@123.pgcom',
|
||||
'pg@postgres.local', 'postgres@pg.blah',
|
||||
'john@doe.com', 'punster@tr.co',
|
||||
'admin@example.com'],
|
||||
check_deliverability=False,
|
||||
expected_data=dict(
|
||||
test_result=True
|
||||
)
|
||||
)
|
||||
)),
|
||||
('Email validation (with deliverability)',
|
||||
dict(
|
||||
data=dict(
|
||||
email_list=['postgres@local.dev', 'pg@pgadminrocks.com',
|
||||
'pg@postgres.local'],
|
||||
check_deliverability=True,
|
||||
expected_data=dict(
|
||||
test_result=False
|
||||
)
|
||||
)
|
||||
)),
|
||||
('Empty email validation (no deliverability)',
|
||||
dict(
|
||||
data=dict(
|
||||
email_list=[''],
|
||||
check_deliverability=False,
|
||||
expected_data=dict(
|
||||
test_result=False
|
||||
)
|
||||
)
|
||||
)),
|
||||
('Empty email validation (with deliverability)',
|
||||
dict(
|
||||
data=dict(
|
||||
email_list=[''],
|
||||
check_deliverability=True,
|
||||
expected_data=dict(
|
||||
test_result=False
|
||||
)
|
||||
)
|
||||
))
|
||||
]
|
||||
|
||||
def runTest(self):
|
||||
|
||||
if config.SERVER_MODE is False:
|
||||
self.skipTest(
|
||||
"Can not run email validation test cases in the DESKTOP mode."
|
||||
)
|
||||
config.CHECK_EMAIL_DELIVERABILITY = self.data['check_deliverability']
|
||||
|
||||
for e in self.data['email_list']:
|
||||
result = validate_email(e)
|
||||
# validate_email returns True if email is valid,
|
||||
# even if non-deliverable. False if email is not valid or
|
||||
# deliverability is turned ON.
|
||||
self.assertEqual(result,
|
||||
self.data['expected_data']['test_result'])
|
@ -7,20 +7,21 @@
|
||||
#
|
||||
##########################################################################
|
||||
|
||||
import re
|
||||
from email_validator import validate_email as email_validate, \
|
||||
EmailNotValidError
|
||||
import config
|
||||
|
||||
|
||||
def validate_email(email):
|
||||
if email == '' or email is None:
|
||||
try:
|
||||
# Validate.
|
||||
valid = email_validate(
|
||||
email, check_deliverability=config.CHECK_EMAIL_DELIVERABILITY)
|
||||
|
||||
# Update with the normalized form.
|
||||
email = valid.email
|
||||
return True
|
||||
except EmailNotValidError as e:
|
||||
# email is not valid, exception message is human-readable
|
||||
print(str(e))
|
||||
return False
|
||||
|
||||
email_filter = re.compile(
|
||||
"^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9]"
|
||||
"(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9]"
|
||||
"(?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"
|
||||
)
|
||||
|
||||
if not email_filter.match(email):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -17,6 +17,7 @@ import sqlite3
|
||||
import shutil
|
||||
from functools import partial
|
||||
import random
|
||||
import importlib
|
||||
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
from testtools.testcase import clone_test_with_new_id
|
||||
@ -1747,3 +1748,34 @@ def create_users_for_parallel_tests(tester):
|
||||
user_id = json.loads(response.data.decode('utf-8'))['id']
|
||||
user_details['user_id'] = user_id
|
||||
return user_details
|
||||
|
||||
|
||||
def module_patch(*args):
|
||||
"""
|
||||
This is a helper function responsible to import a function inside
|
||||
a module with the same name
|
||||
|
||||
e.g. user_info module has user_info function in it.
|
||||
|
||||
:param args:
|
||||
:return:
|
||||
"""
|
||||
|
||||
target = args[0]
|
||||
components = target.split('.')
|
||||
from unittest import mock
|
||||
for i in range(len(components), 0, -1):
|
||||
try:
|
||||
# attempt to import the module
|
||||
imported = importlib.import_module('.'.join(components[:i]))
|
||||
|
||||
# module was imported, let's use it in the patch
|
||||
patch = mock.patch(*args)
|
||||
patch.getter = lambda: imported
|
||||
patch.attribute = '.'.join(components[i:])
|
||||
return patch
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
# did not find a module, just return the default mock
|
||||
return mock.patch(*args)
|
||||
|
Loading…
Reference in New Issue
Block a user