Skip to content

Commit

Permalink
Add check for callable settings
Browse files Browse the repository at this point in the history
  • Loading branch information
iafisher authored and aleksihakli committed Jun 13, 2023
1 parent 498a691 commit 5b235b5
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 0 deletions.
49 changes: 49 additions & 0 deletions axes/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,23 @@ class Messages:
)
BACKEND_INVALID = "You do not have 'axes.backends.AxesStandaloneBackend' or a subclass in your settings.AUTHENTICATION_BACKENDS."
SETTING_DEPRECATED = "You have a deprecated setting {deprecated_setting} configured in your project settings"
CALLABLE_INVALID = "{callable_setting} is not a valid callable."


class Hints:
CACHE_INVALID = None
MIDDLEWARE_INVALID = None
BACKEND_INVALID = "AxesModelBackend was renamed to AxesStandaloneBackend in django-axes version 5.0."
SETTING_DEPRECATED = None
CALLABLE_INVALID = None


class Codes:
CACHE_INVALID = "axes.W001"
MIDDLEWARE_INVALID = "axes.W002"
BACKEND_INVALID = "axes.W003"
SETTING_DEPRECATED = "axes.W004"
CALLABLE_INVALID = "axes.W005"


@register(Tags.security, Tags.caches, Tags.compatibility)
Expand Down Expand Up @@ -153,3 +156,49 @@ def axes_deprecation_check(app_configs, **kwargs): # pylint: disable=unused-arg
pass

return warnings


@register
def axes_conf_check(app_configs, **kwargs): # pylint: disable=unused-argument
warnings = []

callable_settings = [
"AXES_CLIENT_IP_CALLABLE",
"AXES_CLIENT_STR_CALLABLE",
"AXES_LOCKOUT_CALLABLE",
"AXES_USERNAME_CALLABLE",
"AXES_WHITELIST_CALLABLE",
"AXES_COOLOFF_TIME",
"AXES_LOCKOUT_PARAMETERS",
]

for callable_setting in callable_settings:
value = getattr(settings, callable_setting)
if not is_valid_callable(value):
warnings.append(
Warning(
msg=Messages.CALLABLE_INVALID.format(
callable_setting=callable_setting
),
hint=Hints.CALLABLE_INVALID,
id=Codes.CALLABLE_INVALID,
)
)

return warnings


def is_valid_callable(value) -> bool:
if value is None:
return True

if callable(value):
return True

if isinstance(value, str):
try:
import_string(value)
except ImportError:
return False

return True
19 changes: 19 additions & 0 deletions tests/test_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,22 @@ def setUp(self):
def test_deprecated_success_access_log_flag(self):
warnings = run_checks()
self.assertEqual(warnings, [self.disable_success_access_log_warning])


class ConfCheckTestCase(AxesTestCase):
@override_settings(AXES_USERNAME_CALLABLE="module.not_defined")
def test_invalid_import_path(self):
warnings = run_checks()
warning = Warning(
msg=Messages.CALLABLE_INVALID.format(
callable_setting="AXES_USERNAME_CALLABLE"
),
hint=Hints.CALLABLE_INVALID,
id=Codes.CALLABLE_INVALID,
)
self.assertEqual(warnings, [warning])

@override_settings(AXES_COOLOFF_TIME=lambda: 1)
def test_valid_callable(self):
warnings = run_checks()
self.assertEqual(warnings, [])

0 comments on commit 5b235b5

Please sign in to comment.