Keep track of failed login attempts in Django-powered sites.

Related tags

Djangodjango-axes
Overview

django-axes

Jazzband GitHub PyPI release Supported Python versions Supported Django versions Documentation GitHub Actions Coverage

Axes is a Django plugin for keeping track of suspicious login attempts for your Django based website and implementing simple brute-force attack blocking.

The name is sort of a geeky pun, since it can be interpreted as:

  • access, as in monitoring access attempts, or
  • axes, as in tools you can use to hack (generally on wood).

Functionality

Axes records login attempts to your Django powered site and prevents attackers from attempting further logins to your site when they exceed the configured attempt limit.

Axes can track the attempts and persist them in the database indefinitely, or alternatively use a fast and DDoS resistant cache implementation.

Axes can be configured to monitor login attempts by IP address, username, user agent, or their combinations.

Axes supports cool off periods, IP address whitelisting and blacklisting, user account whitelisting, and other features for Django access management.

Documentation

For more information on installation and configuration see the documentation at:

https://django-axes.readthedocs.io/

Issues

If you have questions or have trouble using the app please file a bug report at:

https://github.com/jazzband/django-axes/issues

Contributions

All contributions are welcome!

It is best to separate proposed changes and PRs into small, distinct patches by type so that they can be merged faster into upstream and released quicker.

One way to organize contributions would be to separate PRs for e.g.

  • bugfixes,
  • new features,
  • code and design improvements,
  • documentation improvements, or
  • tooling and CI improvements.

Merging contributions requires passing the checks configured with the CI. This includes running tests and linters successfully on the currently officially supported Python and Django versions.

The test automation is run automatically with GitHub Actions, but you can run it locally with the tox command before pushing commits.

Please note that this is a Jazzband project. By contributing you agree to abide by the Contributor Code of Conduct and follow the guidelines.

Comments
  • Axes settings seems not loaded by django in production

    Axes settings seems not loaded by django in production

    Axes is in INSTALLED_APPS and AUTHENTICATION_BACKENDS. Version : 5.5.0

    When trying to run my CI and just test runner I got this :

    Here is the traceback : Traceback (most recent call last): File "manage.py", line 38, in execute_from_command_line(sys.argv) File "/usr/local/lib/python3.7/site-packages/django/core/management/init.py", line 381, in execute_from_command_line utility.execute() File "/usr/local/lib/python3.7/site-packages/django/core/management/init.py", line 357, in execute django.setup() File "/usr/local/lib/python3.7/site-packages/django/init.py", line 24, in setup apps.populate(settings.INSTALLED_APPS) File "/usr/local/lib/python3.7/site-packages/django/apps/registry.py", line 122, in populate app_config.ready() File "/var/www/jung/badoom/core/apps.py", line 20, in ready autodiscover_modules("signals") File "/usr/local/lib/python3.7/site-packages/django/utils/module_loading.py", line 47, in autodiscover_modules import_module('%s.%s' % (app_config.name, module_to_search)) File "/usr/local/lib/python3.7/importlib/init.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "", line 1006, in _gcd_import File "", line 983, in _find_and_load File "/usr/local/lib/python3.7/site-packages/ddtrace/internal/import_hooks.py", line 215, in wrapped_find_and_load_unlocked return exec_and_call_hooks(module_name, wrapped, args, kwargs) File "/usr/local/lib/python3.7/site-packages/ddtrace/internal/import_hooks.py", line 171, in exec_and_call_hooks return wrapped(*args, **kwargs) File "", line 967, in _find_and_load_unlocked File "", line 677, in _load_unlocked File "", line 728, in exec_module File "", line 219, in _call_with_frames_removed File "/usr/local/lib/python3.7/site-packages/axes/signals.py", line 15, in from axes.handlers.proxy import AxesProxyHandler File "", line 983, in _find_and_load File "/usr/local/lib/python3.7/site-packages/ddtrace/internal/import_hooks.py", line 215, in wrapped_find_and_load_unlocked return exec_and_call_hooks(module_name, wrapped, args, kwargs) File "/usr/local/lib/python3.7/site-packages/ddtrace/internal/import_hooks.py", line 171, in exec_and_call_hooks return wrapped(*args, **kwargs) File "/usr/local/lib/python3.7/site-packages/axes/handlers/proxy.py", line 16, in log = getLogger(settings.AXES_LOGGER) File "/usr/local/lib/python3.7/site-packages/django/conf/init.py", line 80, in getattr val = getattr(self._wrapped, name) AttributeError: 'Settings' object has no attribute 'AXES_LOGGER'

    I know we can skip Axes in test but I would prefer to fix this issue, any insight ?

    needs clarification 
    opened by jeremyrich 31
  • Potential security issues with `get_ip()` changes in v4

    Potential security issues with `get_ip()` changes in v4

    I'm a little concerned by the change to use ipware.ip.get_ip() in v4.

    1. There is no documentation to suggest that django-ipware may need to be configured.
    2. There is now no documentation on the potential attack vector if the proxy doesn't set X-Forwarded-For (or whatever the first header used in IPWARE_META_PRECEDENCE_ORDER is) explicitly, c.f. USE_X_FORWARDED_HOST
    3. ~~django-ipware says to use get_ip() if the server is not accessible on the Internet, see here.~~ (Although looking at the code the distinction between get_ip() and get_real_ip(), the latter doesn't count private IP addresses as "real". What they really mean here is use get_ip() if there are also clients that may connect from an internal private network otherwise use get_real_ip().)
    4. Previously django-axes allowed configuring the maximum number of proxies in case of spoofed entries. This is no longer possible. django-ipware provides get_trusted_ip() but it isn't particularly useful in it's current form.

    It would probably be wise to recommend setting IPWARE_META_PRECEDENCE_ORDER to ['HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR'] or at least indicate that this was the original behaviour. Checking all of these headers by default feels risky.

    Forgive me, but this feels rushed and ill thought through. It was working fine for me and issue #275 and pull request #280 fail to even give any evidence of a problem. Every comment in #275 is regarding AttributeError when looking up META on NoneType - django-ipware is still using request.META. This feels like a push to remove code in favour of a dependency for minor gain.

    documentation 
    opened by ngnpope 24
  • Axes 3.0.0. Fixes #215 #223 #233 #236

    Axes 3.0.0. Fixes #215 #223 #233 #236

    Hi everyone.

    I just did a bunch of changes to use the Django auth signals, so I suppose a lot of things may have changed.

    It is possible to be some broken tests but I already tested on a Django 1.11 project and works pretty fine.

    Please feel free to add comments or suggestions, and help me out fixing or improving tests. I won't have much time to work on them in the next couple weeks, but I would like this to be merged soon.

    any help is very much appreciated.

    opened by camilonova 23
  • Lockouts no longer functioning after upgrading from 5.0.18 to 5.0.19

    Lockouts no longer functioning after upgrading from 5.0.18 to 5.0.19

    (Hey everyone, thanks for making axes such a wonderful project! I know a lot of hard work was put into this!)

    I've been using django-axes for nearly a year (edit: since 4.5.x) without any problems, and recently upgraded from 5.0.18 to 5.0.19 and my unit tests now indicate that lockouts are no longer working.

    The lockouts are based on user login plus IP. We are using axes with django_rest_framework 3.8.2 and django_allauth 0.40.0.

    Some relevant settings:

    AUTHENTICATION_BACKENDS = (
        "axes.backends.AxesBackend",
        "django.contrib.auth.backends.ModelBackend",
        "allauth.account.auth_backends.AuthenticationBackend",
    }
    CACHES = {
        "default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"},
        "axes_cache": {"BACKEND": "django.core.cache.backends.dummy.DummyCache"},
    }
    AXES_CACHE = "axes_cache"
    AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP = True
    

    With axes 5.0.18, after two unsuccessful local attempts against the same login:

    [in]: from axes.models import AccessAttempt
    [in]: qs = AccessAttempt.objects.all()
    [in]: len(qs)
    [out]: 1
    
    [in]: attempt = qs.first()
    [in]: vars(attempt)
    [out]:
    {'_state': <django.db.models.base.ModelState at 0x7fd6214d5dd8>,
     'id': 68,
     'user_agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
     'ip_address': '127.0.0.1',
     'username': '[email protected]',
     'http_accept': 'application/json',
     'path_info': '/account/login/',
     'attempt_time': datetime.datetime(2019, 11, 28, 21, 22, 5, 592513, tzinfo=<UTC>),
     'get_data': '\n---------\n',
     'post_data': '[email protected]\n---------\[email protected]',
     'failures_since_start': 2}
    

    With 5.0.18 both attempts are correctly represented by the same model instance.

    After upgrading to axes 5.0.19, when I run the same test as above:

    [in]: qs = AccessAttempt.objects.all()
    [in]: len(qs)
    [out]: 2
    
    [in]: a_1 = qs.first()
    [in]: a_2 = qs.last()
    [in]: vars(a_1)
    [out]:
    {'_state': <django.db.models.base.ModelState at 0x7f20ebe4ae48>,
     'id': 69,
     'user_agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
     'ip_address': '127.0.0.1',
     'username': '[email protected]',
     'http_accept': 'application/json',
     'path_info': '/account/login/',
     'attempt_time': datetime.datetime(2019, 11, 28, 21, 27, 7, 300416, tzinfo=<UTC>),
     'get_data': '',
     'post_data': '[email protected]',
     'failures_since_start': 1}
    
    [in]: vars(a_2)
    [out]:
    {'_state': <django.db.models.base.ModelState at 0x7f20ebe4aa20>,
     'id': 70,
     'user_agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 Safari/537.36',
     'ip_address': '127.0.0.1',
     'username': '[email protected]',
     'http_accept': 'application/json',
     'path_info': '/account/login/',
     'attempt_time': datetime.datetime(2019, 11, 28, 21, 27, 8, 883077, tzinfo=<UTC>),
     'get_data': '',
     'post_data': '[email protected]',
     'failures_since_start': 1}
    

    With 5.0.19, both attempts with the same login and IP are recorded to separate model instances and there is no lockout on subsequent attempts.

    Has anyone else experienced anything like this?

    documentation bug needs clarification 
    opened by whwkong 16
  • Bugfix #358 credentials in favor of request

    Bugfix #358 credentials in favor of request

    As previously mentioned in #358 the AXES_ONLY_USER_FAILURES setting only works if the login is performed using a Form request. If logging in using JSON, Axes can properly save the failed logins, but is unable to find an existing entry in the axes_attempts table or in cache due to relying on request.POST to find the username.

    I changed this to make use of the credentials or username fields wherever possible, added new tests for thsi behavior and updated the documentation.

    When available, credentials is passed along until it reaches the get_client_username in utils.py. If credentials is not available to be forwarded, but the parsed username from login is available otherwise, a dummy credentials dictionary is created with the settings.AXES_USERNAME_FORM_FIELD key and the username inside it. Only if none of these are availeble the old way to get the username directly from request,POST is attempted. This mainly affects the decorators for the Login forms, but there's neither a good way to access the username otherwise nor will these usually be manipulated to not send a form request for the login.

    Last but not least, I had to introduce a breaking change: The AXES_USERNAME_CALLABLE function now receives the credentials dictionary as additional parameter.

    I think this should also fix #376 as I've just replaced the manual logic for looking up the username from the request with callng get_client_username instead

    bug enhancement 
    opened by mastacheata 16
  • django-reversion compability

    django-reversion compability

    Hi guys,

    following thing: I'm using django-rest-framework and want to secure my backend with axes.

    When I use the default database table type "InnoDB" axes cannot save or update failed attempts in the tables. When I change the table type to "MyIsam", it works.

    I just updated to the latest version. Same as before. Super strange but I couldn't figure out why this happens.

    Best Ronny

    documentation known issue wont fix 
    opened by GitRon 15
  • Django test client compatibility

    Django test client compatibility

    Since version 5, when using the login and force_login methods of the django test client (django version 1.11), exceptions get thrown and tests fail.

    When using force_login() the django test client uses an instance of HttpRequest, but axes requires an AxesHttpRequest.

    from django.test import Client
    client = Client()
    client.force_login(user)
    
    Traceback (most recent call last):
      File "/vagrant/src/project/tests/tests_integration.py", line 87, in setUp
        client.force_login(user)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/test/client.py", line 645, in force_login
        self._login(user, backend)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/test/client.py", line 658, in _login
        login(request, user, backend)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/contrib/auth/__init__.py", line 161, in login
        user_logged_in.send(sender=user.__class__, request=request, user=user)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 193, in send
        for receiver in self._live_receivers(sender)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/dispatch/dispatcher.py", line 193, in <listcomp>
        for receiver in self._live_receivers(sender)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/axes/signals.py", line 26, in handle_user_logged_in
        AxesProxyHandler.user_logged_in(*args, **kwargs)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/axes/handlers/proxy.py", line 52, in user_logged_in
        return cls.get_implementation().user_logged_in(sender, request, user, **kwargs)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/axes/handlers/database.py", line 141, in user_logged_in
        clean_expired_user_attempts(request.axes_attempt_time)
    AttributeError: 'HttpRequest' object has no attribute 'axes_attempt_time'
    

    When using login() the test client uses request=None to authenticate.

    from django.test import Client
    client = Client()
    client.login(user=user.email, password="SecurePassword123")
    
    Traceback (most recent call last):
      File "/vagrant/src/project/tests/tests_integration.py", line 89, in setUp
        client.login(user=user.email, password="SecurePassword123")
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/test/client.py", line 628, in login
        user = authenticate(**credentials)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/contrib/auth/__init__.py", line 70, in authenticate
        user = _authenticate_with_backend(backend, backend_path, request, credentials)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/django/contrib/auth/__init__.py", line 116, in _authenticate_with_backend
        return backend.authenticate(*args, **credentials)
      File "/home/vagrant/.local/share/virtualenvs/vagrant-gKDsaKU3/lib/python3.6/site-packages/axes/backends.py", line 33, in authenticate
        raise AxesBackendRequestParameterRequired('AxesBackend requires a request as an argument to authenticate')
    axes.exceptions.AxesBackendRequestParameterRequired: AxesBackend requires a request as an argument to authenticate
    
    documentation 
    opened by MWedl 15
  • Enable django-axes only for staff/admin site

    Enable django-axes only for staff/admin site

    I would like to only enable django-axes for staff accounts (preferably only admin site). According to the documentation this is currently not possible (I can't find anything about it). Is it true? Thanks!

    enhancement help wanted 
    opened by csdenboer 15
  • use an authentication backend to check if user is locked out.

    use an authentication backend to check if user is locked out.

    @camilonova First Draft for input.

    USAGE

    settings.py

    AUTHENTICATION_BACKENDS = [
        'axes.middleware.DjangoAxesAuthBackend',
        'django.contrib.auth.backends.ModelBackend',
    ]
    

    login view call example

    user = User.objects.get(email=form.cleaned_data['email'])
    response_context = {}
    user = authenticate(
        request=request,
        username=user.username,
        password=form.cleaned_data['password'],
        response_context=response_context
    )
    ...
    if 'error' not in context:
        # if don't have a more specific error, use a generic one.
        context['error'] = 'Incorrect Login Information'
    render(request, 'log_in.html', context)
    
    enhancement 
    opened by markddavidoff 14
  • Logging respects configuration settings

    Logging respects configuration settings

    This PR enhances external logging for the project in three ways:

    • Log messages contain the correct attributes of the request, when VERBOSE = False.
    • Log messages contain detailed information about the request when VERBOSE = True.
    • Adds a log message for successful login if DISABLE_SUCCESS_ACCESS_LOG = False.

    Accurate logging messages are dependent on the configuration. Settings that it looks at:

    • AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP
    • AXES_ONLY_USER_FAILURES
    • USE_USER_AGENT
    • VERBOSE

    Log messages were only accurate for the default setting, which exclusively blocks by IP address.

    Below is an example the before and after, for logs from a lockout based on IP username, where AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP = True.

    Before:

    [2017-04-25 20:20:26,474] [INFO] [axes.watch_login] AXES: BEGIN LOG
    [2017-04-25 20:20:26,474] [INFO] [axes.watch_login] AXES: Using django-axes 2.3.2
    [2017-04-25 20:20:32,361] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 20:20:32,473] [INFO] [axes.watch_login] AXES: New login failure by 10.2.3.1. Creating access record.
    [2017-04-25 20:20:33,841] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 20:20:34,000] [INFO] [axes.watch_login] AXES: Repeated login failure by 10.2.3.1. Updating access record. Count = 2
    [2017-04-25 20:20:35,149] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 20:20:35,290] [INFO] [axes.watch_login] AXES: Repeated login failure by 10.2.3.1. Updating access record. Count = 3
    [2017-04-25 20:20:35,292] [WARNING] [axes.watch_login] AXES: locked out 10.2.3.1 after repeated login attempts.
    

    After:

    [2017-04-25 20:18:27,057] [INFO] [axes.watch_login] AXES: BEGIN LOG
    [2017-04-25 20:18:27,058] [INFO] [axes.watch_login] AXES: Using django-axes 2.3.2
    [2017-04-25 20:18:27,058] [INFO] [axes.watch_login] AXES: blocking by combination of username and IP.
    [2017-04-25 20:18:35,321] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 20:18:35,445] [INFO] [axes.watch_login] AXES: New login failure by [email protected] from 10.2.3.1. Creating access record.
    [2017-04-25 20:18:36,570] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 20:18:36,701] [INFO] [axes.watch_login] AXES: Repeated login failure by [email protected] from 10.2.3.1. Updating access record. Count = 2 of 3
    [2017-04-25 20:18:37,630] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 20:18:37,763] [INFO] [axes.watch_login] AXES: Repeated login failure by [email protected] from 10.2.3.1. Updating access record. Count = 3 of 3
    [2017-04-25 20:18:37,765] [WARNING] [axes.watch_login] AXES: locked out [email protected] from 10.2.3.1 after repeated login attempts.
    

    If VERBOSE is set, then detailed information about the request that triggered the event is logged:

    • Username
    • IP Address
    • User agent
    • Requested path

    This is highly useful information when fed into an external SIEM or logging service, like ELK or Splunk, and used for correlation.

    [2017-04-25 21:50:08,638] [INFO] [axes.watch_login] AXES: BEGIN LOG
    [2017-04-25 21:50:08,638] [INFO] [axes.watch_login] AXES: Using django-axes 2.3.2
    [2017-04-25 21:50:08,638] [INFO] [axes.watch_login] AXES: blocking by combination of username and IP.
    [2017-04-25 21:50:31,896] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 21:50:32,016] [INFO] [axes.watch_login] AXES: New login failure by {user: '[email protected]', ip: '10.2.3.1', user-agent: 'Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1', path: '('/api/auth/login/',)'}. Creating access record.
    [2017-04-25 21:50:33,466] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 21:50:33,589] [INFO] [axes.watch_login] AXES: Repeated login failure by {user: '[email protected]', ip: '10.2.3.1', user-agent: 'Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1', path: '/api/auth/login/'}. Updating access record. Count = 2 of 3
    [2017-04-25 21:50:34,730] [INFO] [axes.watch_login] AXES: Calling decorated function: LoginView
    [2017-04-25 21:50:34,850] [INFO] [axes.watch_login] AXES: Repeated login failure by {user: '[email protected]', ip: '10.2.3.1', user-agent: 'Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1', path: '/api/auth/login/'}. Updating access record. Count = 3 of 3
    [2017-04-25 21:50:34,851] [WARNING] [axes.watch_login] AXES: locked out {user: '[email protected]', ip: '10.2.3.1', user-agent: 'Lynx/2.8.8dev.3 libwww-FM/2.14 SSL-MM/1.4.1', path: '/api/auth/login/'} after repeated login attempts.
    

    Finally, capturing successful authentication events in external services may be desirable to track user sessions, detect when brute force has succeeded, or some other use case. When DISABLE_SUCCESS_ACCESS_LOG = False, a log message will be generated for successful authentication.

    [2017-04-25 22:38:34,545] [INFO] [axes.watch_login] AXES: New login failure by [email protected] from 10.2.3.1. Creating access record.
    [2017-04-25 22:38:36,995] [INFO] [axes.watch_login] AXES: Repeated login failure by [email protected] from 10.2.3.1. Updating access record. Count = 2 of 3
    [2017-04-25 22:38:40,477] [INFO] [axes.watch_login] AXES: Successful login by [email protected] from 10.2.3.1. Creating access record.
    
    opened by SafeEval 14
  • Possible bug in signals.py?

    Possible bug in signals.py?

    https://github.com/jazzband/django-axes/blob/master/axes/signals.py#L59

    Should the following:

            for attempt in attempts:
                failures = max(failures, attempt.failures_since_start)
    

    be modified to:

            for attempt in attempts:
                failures += attempt.failures_since_start
    

    Given that settings.AXES_ONLY_USER_FAILURES maybe return multiple attempts from the same user (different path or data). Wouldn't it make sense for all failed attempts to be summed together? 🤔 💭

    Thanks!

    bug needs clarification 
    opened by charleswhchan 13
  • Bump tox from 4.0.16 to 4.1.2

    Bump tox from 4.0.16 to 4.1.2

    Bumps tox from 4.0.16 to 4.1.2.

    Release notes

    Sourced from tox's releases.

    4.1.2

    What's Changed

    Full Changelog: https://github.com/tox-dev/tox/compare/4.1.1...4.1.2

    4.1.1

    What's Changed

    Full Changelog: https://github.com/tox-dev/tox/compare/4.1.0...4.1.1

    4.1.0

    What's Changed

    New Contributors

    Full Changelog: https://github.com/tox-dev/tox/compare/4.0.19...4.1.0

    4.0.18

    What's Changed

    Full Changelog: https://github.com/tox-dev/tox/compare/4.0.17...4.0.18

    4.0.17

    What's Changed

    New Contributors

    Full Changelog: https://github.com/tox-dev/tox/compare/4.0.16...4.0.17

    Changelog

    Sourced from tox's changelog.

    v4.1.2 (2022-12-30)

    Bugfixes - 4.1.2

    - Fix ``--skip-missing-interpreters`` behaviour - by :user:`q0w`. (:issue:`2649`)
    - Restore tox 3 behaviour of showing the output of pip freeze, however now only active when running inside a CI
      environment - by :user:`gaborbernat`. (:issue:`2685`)
    - Fix extracting extras from markers with many extras - by :user:`q0w`. (:issue:`2791`)
    

    v4.1.1 (2022-12-29)

    Bugfixes - 4.1.1

    • Fix logging error with emoji in git branch name. (:issue:2768)

    Improved Documentation - 4.1.1

    - Add faq entry about re-use of environments - by :user:`jugmac00`. (:issue:`2788`)
    

    v4.1.0 (2022-12-29)

    Features - 4.1.0

    - ``-f`` can be used multiple times and on hyphenated factors (e.g. ``-f py311-django -f py39``) - by :user:`sirosen`. (:issue:`2766`)
    

    Improved Documentation - 4.1.0 </code></pre> <ul> <li>Fix a grammatical typo in docs/user_guide.rst. (:issue:<code>2787</code>)</li> </ul> <h2>v4.0.19 (2022-12-28)</h2> <p>Bugfixes - 4.0.19</p> <pre><code>- Create temp_dir if not exists - by :user:q0w. (:issue:2770)

    v4.0.18 (2022-12-26)

    Bugfixes - 4.0.18 </code></pre> <ul> <li>Strip leading and trailing whitespace when parsing elements in requirement files - by :user:<code>gaborbernat</code>. (:issue:<code>2773</code>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary>

    <ul> <li><a href="https://github.com/tox-dev/tox/commit/6253d6220486e17c6132f613cc6218c87b084417"><code>6253d62</code></a> release 4.1.2</li> <li><a href="https://github.com/tox-dev/tox/commit/196b20de4c969a163d34692d8a5d646cad4717d6"><code>196b20d</code></a> Fix extracting extras from markers with many extras (<a href="https://github-redirect.dependabot.com/tox-dev/tox/issues/2792">#2792</a>)</li> <li><a href="https://github.com/tox-dev/tox/commit/a3d3ec042d38195392841a9112911c2bde3587d1"><code>a3d3ec0</code></a> Show installed packages after setup in CI envs (<a href="https://github-redirect.dependabot.com/tox-dev/tox/issues/2794">#2794</a>)</li> <li><a href="https://github.com/tox-dev/tox/commit/d8c4cb0ffa1999b5d6466e0099dab76f242b1ba8"><code>d8c4cb0</code></a> Fix --skip-missing-interpreters (<a href="https://github-redirect.dependabot.com/tox-dev/tox/issues/2793">#2793</a>)</li> <li><a href="https://github.com/tox-dev/tox/commit/1d739a2641bcb0545815afbabf8b3da9694ec0ff"><code>1d739a2</code></a> release 4.1.1</li> <li><a href="https://github.com/tox-dev/tox/commit/b49d11867ab6bd7219c5b2c50f610e7829395975"><code>b49d118</code></a> Fix logging error with emoji in git branch name. (<a href="https://github-redirect.dependabot.com/tox-dev/tox/issues/2790">#2790</a>)</li> <li><a href="https://github.com/tox-dev/tox/commit/c83819262b4b739899af8a0bd7b6f32442344e4a"><code>c838192</code></a> Add faq entry about re-use of environments (<a href="https://github-redirect.dependabot.com/tox-dev/tox/issues/2789">#2789</a>)</li> <li><a href="https://github.com/tox-dev/tox/commit/e0aed508607d34559610fbb0d2b4fd038da9c11b"><code>e0aed50</code></a> release 4.1.0</li> <li><a href="https://github.com/tox-dev/tox/commit/6cdd99cc3ce4fc73455374b40f2dd8a95ef101c5"><code>6cdd99c</code></a> Improved factor selection to allow multiple uses of <code>-f</code> for &quot;OR&quot; and to allo...</li> <li><a href="https://github.com/tox-dev/tox/commit/6f056cafcca6cee4b23a35fdfc2044647c99e8d7"><code>6f056ca</code></a> Update user_guide.rst (<a href="https://github-redirect.dependabot.com/tox-dev/tox/issues/2787">#2787</a>)</li> <li>Additional commits viewable in <a href="https://github.com/tox-dev/tox/compare/4.0.16...4.1.2">compare view</a></li> </ul> </details>

    <br />

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    python dependencies 
    opened by dependabot[bot] 0
  • Bump coverage from 7.0.0 to 7.0.1

    Bump coverage from 7.0.0 to 7.0.1

    Bumps coverage from 7.0.0 to 7.0.1.

    Changelog

    Sourced from coverage's changelog.

    Version 7.0.1 — 2022-12-23

    • When checking if a file mapping resolved to a file that exists, we weren't considering files in .whl files. This is now fixed, closing issue 1511_.

    • File pattern rules were too strict, forbidding plus signs and curly braces in directory and file names. This is now fixed, closing issue 1513_.

    • Unusual Unicode or control characters in source files could prevent reporting. This is now fixed, closing issue 1512_.

    • The PyPy wheel now installs on PyPy 3.7, 3.8, and 3.9, closing issue 1510_.

    .. _issue 1510: nedbat/coveragepy#1510 .. _issue 1511: nedbat/coveragepy#1511 .. _issue 1512: nedbat/coveragepy#1512 .. _issue 1513: nedbat/coveragepy#1513

    .. _changes_7-0-0:

    Commits
    • c5cda3a docs: releases take a little bit longer now
    • 9d4226e docs: latest sample HTML report
    • 8c77758 docs: prep for 7.0.1
    • da1b282 fix: also look into .whl files for source
    • d327a70 fix: more information when mapping rules aren't working right.
    • 35e249f fix: certain strange characters caused reporting to fail. #1512
    • 152cdc7 fix: don't forbid plus signs in file names. #1513
    • 31513b4 chore: make upgrade
    • 873b059 test: don't run tests on Windows PyPy-3.9
    • 5c5caa2 build: PyPy wheel now installs on 3.7, 3.8, and 3.9. #1510
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    python dependencies 
    opened by dependabot[bot] 0
  • Migration 007 relation

    Migration 007 relation "axes_accessattempt" does not exist

    Python version: 3.10.8 Django Version: 4.0.8 Django-axes version: 5.40.0

    Scenario: When upgrading from django-axes 5.39.0 to django-axes 5.40.0, with the django version of 4.0.8 remaining constant, we're encountering this exception below when trying to run all migrations in order on a fresh database. Reverting to django-axes 5.39.0 causes this error to disappear.

    I've previously searched for errors similar to this and found that this one might be tangentially related, but it also seems to predate the 5.40.0 version release, and may be specific to django 4.1, which is not the case here.

    Snippet of exception below:

    File "/.venv/lib/python3.10/site-packages/axes/migrations/0007_alter_accessattempt_unique_together.py", line 18, in deduplicate_attempts
        for attempt in duplicated_attempts:
      File "/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 320, in __iter__
        self._fetch_all()
      File "/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 1507, in _fetch_all
        self._result_cache = list(self._iterable_class(self))
      File "/.venv/lib/python3.10/site-packages/django/db/models/query.py", line 130, in __iter__
        for row in compiler.results_iter(
      File "/.venv/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1312, in results_iter
        results = self.execute_sql(
      File "/.venv/lib/python3.10/site-packages/django/db/models/sql/compiler.py", line 1361, in execute_sql
        cursor.execute(sql, params)
      File "/.venv/lib/python3.10/site-packages/django/db/backends/utils.py", line 67, in execute
        return self._execute_with_wrappers(
      File "/.venv/lib/python3.10/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers
        return executor(sql, params, many, context)
      File "/.venv/lib/python3.10/site-packages/django_read_only/__init__.py", line 77, in blocker
        return execute(sql, params, many, context)
      File "/.venv/lib/python3.10/site-packages/django/db/backends/utils.py", line 84, in _execute
        with self.db.wrap_database_errors:
      File "/.venv/lib/python3.10/site-packages/django/db/utils.py", line 91, in __exit__
        raise dj_exc_value.with_traceback(traceback) from exc_value
      File "/.venv/lib/python3.10/site-packages/django/db/backends/utils.py", line 89, in _execute
        return self.cursor.execute(sql, params)
    django.db.utils.ProgrammingError: relation "axes_accessattempt" does not exist
    LINE 1: ...NT("axes_accessattempt"."id") AS "id__count" FROM "axes_acce...
    
    bug needs clarification 
    opened by js-truework 7
  • Unit Testing

    Unit Testing

    I get the error "AXES: New login failure by {username: "None", ip_address: "None", user_agent: "", path_info: ""}. Created new record in the database." when running unit test with Axes backend. The test runs successfully, but how can I fix the error?

       def test_admin(self):
             request = HttpRequest()
             authenticate(
                   request,
                  username=self.user.username,
                  password=self.user.password,
             )
    
        self.assertTrue(self.admin_user.is_authenticated)
        self.assertEqual(self.admin_user.username, "admin_1")
        self.assertTrue(self.admin_user.is_superuser)
        self.assertNotEqual(self.admin_user.is_staff, False)
    
    opened by edmundrotimi 0
  • Cannot use Token-based Authentication Backend unless AXES_ONLY_USER_FAILURES is set to True.

    Cannot use Token-based Authentication Backend unless AXES_ONLY_USER_FAILURES is set to True.

    I am running into a similar issue as #597 where I am using a Token Authentication Backend along side User-based authentication backends and I want to use Axes only for those User-based backends. I am running into an issue where my token based authentication will generate user_login_failed callbacks and as a result try and create AccessAttempt records with a username of "None" (a string).

    I can work around this by setting AXES_ONLY_USER_FAILURES to True, however I really would like to do IP-based blocking (maybe AXES_LOCK_OUT_BY_USER_OR_IP or even just IP-based lockouts instead.

    opened by Kraust 0
Releases(5.40.1)
Owner
Jazzband
We are all part of this
Jazzband
a little task queue for python

a lightweight alternative. huey is: a task queue (2019-04-01: version 2.0 released) written in python (2.7+, 3.4+) clean and simple API redis, sqlite,

Charles Leifer 4.3k Dec 29, 2022
A django model and form field for normalised phone numbers using python-phonenumbers

django-phonenumber-field A Django library which interfaces with python-phonenumbers to validate, pretty print and convert phone numbers. python-phonen

Stefan Foulis 1.3k Dec 31, 2022
RestApi With Django 3.2 And Django Rest Framework

RestApi-With-Django-3.2-And-Django-Rest-Framework Description This repository is a Software of Development with Python. Virtual Using pipenv, virtuale

Daniel Arturo Alejo Alvarez 6 Aug 02, 2022
Indonesia's negative news detection using gaussian naive bayes with Django+Scikir Learn

Introduction Indonesia's negative news detection using gaussian naive bayes build with Django and Scikit Learn. There is also any features, are: Input

Harifzi Ham 1 Dec 30, 2021
A CTF leaderboard for the submission of flags during a CTF challenge. Built using Django.

🚩 CTF Leaderboard The goal of this project is to provide a simple web page to allow the participants of an CTF to enter their found flags. Also the l

Maurice Bauer 2 Jan 17, 2022
Updates redisearch instance with igdb data used for kimosabe

igdb-pdt Update RediSearch with IGDB games data in the following Format: { "game_slug": { "name": "game_name", "cover": "igdb_coverart_url",

6rotoms 0 Jul 30, 2021
A Django Demo Project of Students Management System

Django_StudentMS A Django Demo Project of Students Management System. From NWPU Seddon for DB Class Pre. Seddon simplify the code in 2021/10/17. Hope

2 Dec 08, 2021
A real-time photo feed using Django and Pusher

BUILD A PHOTO FEED USING DJANGO Here, we will learn about building a photo feed using Django. This is similar to instagram, but a stripped off version

samuel ogundipe 4 Jan 01, 2020
Loguru is an exceeding easy way to do logging in Python

Django Easy Logging Easy Django logging with Loguru Loguru is an exceeding easy way to do logging in Python. django-easy-logging makes it exceedingly

Neutron Sync 8 Oct 17, 2022
A Django Online Library Management Project.

Why am I doing this? I started learning 📖 Django few months back, and this is a practice project from MDN Web Docs that touches the aspects of Django

1 Nov 13, 2021
Easy thumbnails for Django

Easy Thumbnails A powerful, yet easy to implement thumbnailing application for Django 1.11+ Below is a quick summary of usage. For more comprehensive

Chris Beaven 1.3k Dec 30, 2022
REST API con Python, Django y MySQL (GET, POST, PUT, DELETE)

django_api_mysql REST API con Python, Django y MySQL (GET, POST, PUT, DELETE) REST API con Python, Django y MySQL (GET, POST, PUT, DELETE)

Andrew 1 Dec 28, 2021
A middleware to log the requests and responses using loguru.

Django Loguru The extension was based on another one and added some extra flavours. One of the biggest problems with the apps is the logging and that

Tiago Silva 9 Oct 11, 2022
Sistema administrador de contranas desarrollador en Django

Sistema Contrasenas Desarrolado en Django Proyecto sistema de administracion de contraseñas, de la experiencia educativa Programacion Segura Descripci

Ibrain Rodriguez Espinoza 1 Sep 24, 2022
A music recommendation REST API which makes a machine learning algorithm work with the Django REST Framework

music-recommender-rest-api A music recommendation REST API which makes a machine learning algorithm work with the Django REST Framework How it works T

The Reaper 1 Sep 28, 2021
Boilerplate Django Blog for production deployments!

CFE Django Blog THIS IS COMING SOON This is boilerplate code that you can use to learn how to bring Django into production. TLDR; This is definitely c

Coding For Entrepreneurs 26 Dec 09, 2022
Automatic class scheduler for Texas A&M written with Python+Django and React+Typescript

Rev Registration Description Rev Registration is an automatic class scheduler for Texas A&M, aimed at easing the process of course registration by gen

Aggie Coding Club 21 Nov 15, 2022
Django-Text-to-HTML-converter - The simple Text to HTML Converter using Django framework

Django-Text-to-HTML-converter This is the simple Text to HTML Converter using Dj

Nikit Singh Kanyal 6 Oct 09, 2022
Wagtail - Vue - Django : The initial environment of full-stack local dev web app with wagtail and vue

Wagtail - Vue - Django : The initial environment of full-stack local dev web app with wagtail and vue. A demo to show how to use .vue files inside django app.

Quang PHAM 2 Oct 20, 2022
Radically simplified static file serving for Python web apps

WhiteNoise Radically simplified static file serving for Python web apps With a couple of lines of config WhiteNoise allows your web app to serve its o

Dave Evans 2.1k Dec 15, 2022