internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: jazzband/django-axes

Issue:
`AXES_ONLY_USER_FAILURES=True` doesn't seem to cause lockout
Issue: When `AXES_ONLY_USER_FAILURES=True`, no `AccessAttempt` objects are created and therefore never actually locked out. See: https://github.com/jazzband/django-axes/blob/ca55a6ef16acc2f8f5f0501de4ef8f0d2ccd6129/axes/decorators.py#L431

Settings:
`AXES_ONLY_USER_FAILURES=True`

Reproducible steps:
1. Attempt to login with X username 3 times with a wrong password (default `AXES_LOGIN_FAILURE_LIMIT`)
2. Upon third attempt you see the lockout screen/message
3. Either refresh the page, or go back to admin URL
4. You can continue to try and login for an infinite(?) number of times for username X
5. You can then login with username X using the correct password


Discussion:
It seems like after `n` attempts, we're redirected to the `AXES_LOCKOUT_URL` but all access attempts are deleted... The problem is in the logic that attempts to revoke trust in existing records in [axes/decorators.py](https://github.com/jazzband/django-axes/blob/ca55a6ef16acc2f8f5f0501de4ef8f0d2ccd6129/axes/decorators.py#L421). If `AXES_ONLY_USER_FAILURES` is `True` it simply doesn't recreate the failed access attempts and we're left with the user not being locked out any more. I'm not sure I understand why this check is even necessary? Surely if we're only interested in user failures, we simply ignore the IP address on the attempts when we're counting failures?

Resolving patch:
diff --git a/axes/decorators.py b/axes/decorators.py
--- a/axes/decorators.py
+++ b/axes/decorators.py
@@ -433,19 +433,20 @@ def create_new_failure_records(request, failures):
     ua = request.META.get('HTTP_USER_AGENT', '<unknown>')[:255]
     username = request.POST.get(USERNAME_FORM_FIELD, None)
 
-    # record failed attempt from this IP if not AXES_ONLY_USER_FAILURES
-    if not AXES_ONLY_USER_FAILURES:
-        AccessAttempt.objects.create(
-            user_agent=ua,
-            ip_address=ip,
-            username=username,
-            get_data=query2str(request.GET),
-            post_data=query2str(request.POST),
-            http_accept=request.META.get('HTTP_ACCEPT', '<unknown>'),
-            path_info=request.META.get('PATH_INFO', '<unknown>'),
-            failures_since_start=failures,
-        )
-        log.info('AXES: New login failure by %s. Creating access record.' % (ip,))
+    # Record failed attempt. Whether or not the IP address or user agent is
+    # used in counting failures is handled elsewhere, so we just record
+    # everything here.
+    AccessAttempt.objects.create(
+        user_agent=ua,
+        ip_address=ip,
+        username=username,
+        get_data=query2str(request.GET),
+        post_data=query2str(request.POST),
+        http_accept=request.META.get('HTTP_ACCEPT', '<unknown>'),
+        path_info=request.META.get('PATH_INFO', '<unknown>'),
+        failures_since_start=failures,
+    )
+    log.info('AXES: New login failure by %s. Creating access record.' % (ip,))
 
 
 def create_new_trusted_record(request):


Test patch:
Repository: jazzband/django-axes

Issue:
"pip install django-axes" install package missing backends.py
I installed axes today using command "pip install django-axes". The package it installs in my site-packages does not contain the backends.py file. I copied the backends.py in the latest github repo but I got the following error message when I tried to connect to my admin login page:

ImportError at /admin/login/
cannot import name 'get_lockout_message'


Discussion:
Hi @bwapeup, the `backends` file is not yet in the release, only in the upstream repo. We're baking a new release with some additions. Sorry for the inconvenience!
You might want to point the pip release to an earlier version or at least remove the migration files from the broken version. I had followed the steps in the docs and by the time I discovered that this app was missing the backends.py file, the migrations have been done and the tables have been created in my db. 

Resolving patch:
diff --git a/axes/__init__.py b/axes/__init__.py
--- a/axes/__init__.py
+++ b/axes/__init__.py
@@ -1,4 +1,4 @@
-__version__ = '4.1.0'
+__version__ = '4.2.0'
 
 default_app_config = 'axes.apps.AppConfig'
 
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -56,9 +56,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '4.1.0'
+version = '4.2.0'
 # The full version, including alpha/beta/rc tags.
-release = '4.1.0'
+release = '4.2.0'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.


Test patch:
Repository: jazzband/django-axes

Issue:
Release 4.5.0
If everyone is OK with the current implementation for the `credentials`, we can release a version 4.5.0. If iteration on the work is needed, please raise any concerns you have here.

The contents of the changes for 4.5.0 from the current version are available for review in here:

https://github.com/jazzband/django-axes/compare/4.4.3...development


Discussion:
Ping @markddavidoff. 

@mastacheata can you check the changes as well?

Resolving patch:
diff --git a/axes/__init__.py b/axes/__init__.py
--- a/axes/__init__.py
+++ b/axes/__init__.py
@@ -1,6 +1,6 @@
 from __future__ import unicode_literals
 
-__version__ = '4.4.3'
+__version__ = '4.5.0'
 
 default_app_config = 'axes.apps.AppConfig'
 


Test patch:
Repository: jazzband/django-axes

Issue:
Update author, contributor, and licence information
Currently we have some outdated and mismatching author and copyright information in a few different places for the Axes project:

- the [LICENSE file](https://github.com/jazzband/django-axes/blob/master/LICENSE) lists copyright holders Josh VanderLinden for 2008 and Philip Neustrom for 2009, but no mentions after that,
- the [setup file](https://github.com/jazzband/django-axes/blob/master/setup.py) lists a lot more authors, and
- the [documentation configuration file](https://github.com/jazzband/django-axes/blob/master/docs/conf.py) lists only the Jazzband organization with year 2016.

Ideally, the author and copyright information could be harmonized so that it would be easier for users to know who has copyright on what parts of the program and what kind of authorship should be mentioned for the project.

Should the project just list Jazzband organization as the copyright holder and author from 2016 onwards and refer communications to the Jazzband organization? Is there a mailing list that could be used in e.g. the `setup.py` file for the `author` field? Can the `LICENSE` file just be updated with more recent data, and is Jazzband a proper entry in there?

@jezdez @camilonova do you know how the copyright notices, authorship, and licensing should be handled in the Jazzband projects?

The main reason I am bringing this up is that I think it would be nice to have all parts of the project referring to the same information in the same fashion. 

Documenting the usable practices in the Jazzband organization for these things would also be nice, at least I didn't find any mentions on licensing or authorship on the Jazzband site.


Discussion:

Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -21,7 +21,6 @@
         'Camilo Nova',
         'Aleksi Hakli',
     ]),
-    author_email='codekoala@gmail.com',
     maintainer='Jazzband',
     maintainer_email='security@jazzband.co',
     url='https://github.com/jazzband/django-axes',


Test patch:
Repository: jazzband/django-axes

Issue:
Single '}' encountered in format string
We had someone trying to be "smart" and trying to login with a specially crafted username. e.g. `butterfly.. },,,`

This resulted in a `ValueError` exception (`Single '}' encountered in format string`)
in axes/helpers.py in get_client_str at line 230 after being dispatched from `handle_user_login_failed`



Discussion:
Hey! Thanks for reporting. This needs to be checked ASAP as getting format strings in this flow is a possible security flaw. This seems related to logging in [`get_client_str`](https://github.com/jazzband/django-axes/blob/master/axes/helpers.py#L241).

Resolving patch:
diff --git a/axes/helpers.py b/axes/helpers.py
--- a/axes/helpers.py
+++ b/axes/helpers.py
@@ -230,15 +230,10 @@ def get_client_str(
         path_info = path_info[0]
     client_dict["path_info"] = path_info
 
-    # Template the internal dictionary representation into a readable and concatenated key: "value" format
+    # Template the internal dictionary representation into a readable and concatenated {key: "value"} format
     template = ", ".join(f'{key}: "{value}"' for key, value in client_dict.items())
-
-    # Wrap the internal dict into a single {key: "value"} bracing in the output
-    # which requires double braces when done with the Python string templating system
-    # i.e. {{key: "value"}} becomes {key: "value"} when run through a .format() call
-    template = "{{" + template + "}}"
-
-    return template.format(client_dict)
+    template = "{" + template + "}"
+    return template
 
 
 def get_query_str(query: Type[QueryDict], max_length: int = 1024) -> str:


Test patch:
diff --git a/axes/tests/test_utils.py b/axes/tests/test_utils.py
--- a/axes/tests/test_utils.py
+++ b/axes/tests/test_utils.py
@@ -97,6 +97,20 @@ def test_verbose_ip_only_client_details(self):
 
         self.assertEqual(expected, actual)
 
+    @override_settings(AXES_VERBOSE=True)
+    def test_imbalanced_quotes(self):
+        username = "butterfly.. },,,"
+        ip_address = "127.0.0.1"
+        user_agent = "Googlebot/2.1 (+http://www.googlebot.com/bot.html)"
+        path_info = "/admin/"
+
+        expected = self.get_expected_client_str(
+            username, ip_address, user_agent, path_info
+        )
+        actual = get_client_str(username, ip_address, user_agent, path_info)
+
+        self.assertEqual(expected, actual)
+
     @override_settings(AXES_VERBOSE=True)
     def test_verbose_ip_only_client_details_tuple(self):
         username = "test@example.com"
Repository: jazzband/django-axes

Issue:
ModuleNotFoundError: No module named 'ipware.ip2'  -- error in django-axes==5.0.7, Django==2.2, Python==3.8
`django-ipware` has no module `ipware.ip2` in recent version. Please fix this ASAP.

In the `helpers.py` file import `ipware.ip2` is breaking for new version of django-ipware.

```
django_1         | Traceback (most recent call last):
django_1         |   File "manage.py", line 30, in <module>
django_1         |     execute_from_command_line(sys.argv)
django_1         |   File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
django_1         |     utility.execute()
django_1         |   File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 357, in execute
django_1         |     django.setup()
django_1         |   File "/usr/local/lib/python3.7/site-packages/django/__init__.py", line 24, in setup
django_1         |     apps.populate(settings.INSTALLED_APPS)
django_1         |   File "/usr/local/lib/python3.7/site-packages/django/apps/registry.py", line 122, in populate
django_1         |     app_config.ready()
django_1         |   File "/usr/local/lib/python3.7/site-packages/axes/apps.py", line 47, in ready
django_1         |     from axes import checks, signals  # noqa
django_1         |   File "/usr/local/lib/python3.7/site-packages/axes/signals.py", line 11, in <module>
django_1         |     from axes.handlers.proxy import AxesProxyHandler
django_1         |   File "/usr/local/lib/python3.7/site-packages/axes/handlers/proxy.py", line 7, in <module>
django_1         |     from axes.handlers.base import AxesHandler
django_1         |   File "/usr/local/lib/python3.7/site-packages/axes/handlers/base.py", line 2, in <module>
django_1         |     from axes.helpers import (
django_1         |   File "/usr/local/lib/python3.7/site-packages/axes/helpers.py", line 11, in <module>
django_1         |     import ipware.ip2
django_1         | ModuleNotFoundError: No module named 'ipware.ip2'

```



Discussion:
Same in here

404... https://github.com/un33k/django-ipware/blob/master/ipware/ip2.py

I hope you can fix this soon guys... our prod envs can not be deployed.. :(

Same here, please update django-ipware dependency
I confirm the issue. Quickfix: change ipware.ip2 to ipware.ip in the helpers file (twice in the file).

Resolving patch:
diff --git a/axes/helpers.py b/axes/helpers.py
--- a/axes/helpers.py
+++ b/axes/helpers.py
@@ -15,7 +15,7 @@
 from django.shortcuts import render
 from django.utils.module_loading import import_string
 
-import ipware.ip2
+import ipware.ip
 
 from axes.conf import settings
 from axes.models import AccessBase
@@ -156,7 +156,7 @@ def get_client_ip_address(request) -> str:
     and parameters can be configured in the Axes package.
     """
 
-    client_ip_address, _ = ipware.ip2.get_client_ip(
+    client_ip_address, _ = ipware.ip.get_client_ip(
         request,
         proxy_order=settings.AXES_PROXY_ORDER,
         proxy_count=settings.AXES_PROXY_COUNT,


Test patch:
Repository: jazzband/django-axes

Issue:
Error fetching command 'axes_reset_user'
Hello,

after updating to the latest django-axes (5.6.1) i've got some errors applying its migrations, since the software i'm developing is still in test i had the opportunity to start over and deleting database tables and migrations.
Unfortunately i still got this error every time i try to access django's management commands:

Error fetching command 'axes_reset_user': name 'axes_reset_username' is not defined
Command 'axes_reset_user' skipped

I am using Django 3.1.1 with postgres, before this update everything was working as it should.
Can i help in some way to understand what's happening?

Thanks
Marco


Discussion:
This is the content of axes_reset_user.py

axes_reset_username.py  # type: ignore # pylint: disable=all

Probably caused by https://github.com/jazzband/django-axes/commit/baed1377f21c13999b9ef0d217a14848a217fa2c

Will need to roll back the changes in the management command file and release 5.6.2 to fix this.

Thanks for reporting! Let’s see if we can add a regression test for this.

Resolving patch:
diff --git a/axes/management/commands/axes_reset_user.py b/axes/management/commands/axes_reset_user.py
deleted file mode 100644
--- a/axes/management/commands/axes_reset_user.py
+++ /dev/null
@@ -1 +0,0 @@
-axes_reset_username.py  # type: ignore # pylint: disable=all
diff --git a/axes/management/commands/axes_reset_user.py b/axes/management/commands/axes_reset_user.py
new file mode 120000
--- /dev/null
+++ b/axes/management/commands/axes_reset_user.py
@@ -0,0 +1 @@
+axes_reset_username.py
\ No newline at end of file


Test patch:
Repository: jazzband/django-axes

Issue:
Return CORS headers to avoid CORS policy error
When calling backend running axes from other server or local dev environment over AJAX a CORS policy error is returned.
----
Access to fetch at 'http://0.0.0.0:8005/de/graphql/' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.


Discussion:

Resolving patch:
diff --git a/axes/conf.py b/axes/conf.py
--- a/axes/conf.py
+++ b/axes/conf.py
@@ -115,3 +115,6 @@
     "AXES_META_PRECEDENCE_ORDER",
     getattr(settings, "IPWARE_META_PRECEDENCE_ORDER", ("REMOTE_ADDR",)),
 )
+
+# set CORS allowed origins when calling authentication over ajax
+settings.AXES_ALLOWED_CORS_ORIGINS = getattr(settings, "AXES_ALLOWED_CORS_ORIGINS", "*")
diff --git a/axes/helpers.py b/axes/helpers.py
--- a/axes/helpers.py
+++ b/axes/helpers.py
@@ -342,7 +342,15 @@ def get_lockout_response(request, credentials: dict = None) -> HttpResponse:
         )
 
     if request.META.get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest":
-        return JsonResponse(context, status=status)
+        json_response = JsonResponse(context, status=status)
+        json_response[
+            "Access-Control-Allow-Origin"
+        ] = settings.AXES_ALLOWED_CORS_ORIGINS
+        json_response["Access-Control-Allow-Methods"] = "POST, OPTIONS"
+        json_response[
+            "Access-Control-Allow-Headers"
+        ] = "Origin, Content-Type, Accept, Authorization, x-requested-with"
+        return json_response
 
     if settings.AXES_LOCKOUT_TEMPLATE:
         return render(request, settings.AXES_LOCKOUT_TEMPLATE, context, status=status)


Test patch:
Repository: jazzband/django-axes

Issue:
Missing German translation for "Access failures"
I just realised that this translation is missing. I'd go with something like "Fehlgeschlagene Zugriffsversuche" (plural) and "Fehlgeschlagener Zugriffsversuch" (singular)

Best  
Ronny


Discussion:
Hi @GitRon and thanks for reporting the issue. The proposal sounds good, would you like to a open a PR for it?

Resolving patch:
diff --git a/axes/handlers/base.py b/axes/handlers/base.py
--- a/axes/handlers/base.py
+++ b/axes/handlers/base.py
@@ -158,7 +158,7 @@ def reset_attempts(
         Resets access attempts that match the given IP address or username.
 
         This method makes more sense for the DB backend, but as it is used by the ProxyHandler
-        (via inherent), it needs to be defined here so we get compliant with all proxy methods.
+        (via inherent), it needs to be defined here, so we get compliant with all proxy methods.
 
         Please overwrite it on each specialized handler as needed.
         """
@@ -169,7 +169,7 @@ def reset_logs(self, *, age_days: Optional[int] = None) -> int:
         Resets access logs that are older than given number of days.
 
         This method makes more sense for the DB backend, but as it is used by the ProxyHandler
-        (via inherent), it needs to be defined here so we get compliant with all proxy methods.
+        (via inherent), it needs to be defined here, so we get compliant with all proxy methods.
 
         Please overwrite it on each specialized handler as needed.
         """
@@ -180,7 +180,7 @@ def reset_failure_logs(self, *, age_days: Optional[int] = None) -> int:
         Resets access failure logs that are older than given number of days.
 
         This method makes more sense for the DB backend, but as it is used by the ProxyHandler
-        (via inherent), it needs to be defined here so we get compliant with all proxy methods.
+        (via inherent), it needs to be defined here, so we get compliant with all proxy methods.
 
         Please overwrite it on each specialized handler as needed.
         """
@@ -193,7 +193,7 @@ def remove_out_of_limit_failure_logs(
         AXES_ACCESS_FAILURE_LOG_PER_USER_LIMIT for user username.
 
         This method makes more sense for the DB backend, but as it is used by the ProxyHandler
-        (via inherent), it needs to be defined here so we get compliant with all proxy methods.
+        (via inherent), it needs to be defined here, so we get compliant with all proxy methods.
 
         Please overwrite it on each specialized handler as needed.
 


Test patch:
Repository: jazzband/django-axes

Issue:
Migration 0007 missing db alias
Migration [0007](https://github.com/jazzband/django-axes/blob/master/axes/migrations/0007_alter_accessattempt_unique_together.py) is missing the use of a database alias resulting in issues if the database option is used when applying.

As per [docs](https://docs.djangoproject.com/en/4.1/ref/migration-operations/#runpython) `db_alias = schema_editor.connection.alias` should be used.


Discussion:

Resolving patch:
diff --git a/axes/migrations/0007_alter_accessattempt_unique_together.py b/axes/migrations/0007_alter_accessattempt_unique_together.py
--- a/axes/migrations/0007_alter_accessattempt_unique_together.py
+++ b/axes/migrations/0007_alter_accessattempt_unique_together.py
@@ -6,21 +6,23 @@
 
 def deduplicate_attempts(apps, schema_editor):
     AccessAttempt = apps.get_model("axes", "AccessAttempt")
+    db_alias = schema_editor.connection.alias
     duplicated_attempts = (
-        AccessAttempt.objects.values("username", "user_agent", "ip_address")
+        AccessAttempt.objects.using(db_alias)
+        .values("username", "user_agent", "ip_address")
         .annotate(Count("id"))
         .order_by()
         .filter(id__count__gt=1)
     )
 
     for attempt in duplicated_attempts:
-        redundant_attempts = AccessAttempt.objects.filter(
+        redundant_attempts = AccessAttempt.objects.using(db_alias).filter(
             username=attempt["username"],
             user_agent=attempt["user_agent"],
             ip_address=attempt["ip_address"],
         )[1:]
         for redundant_attempt in redundant_attempts:
-            redundant_attempt.delete()
+            redundant_attempt.delete(using=db_alias)
 
 
 class Migration(migrations.Migration):


Test patch:
Repository: jazzband/django-axes

Issue:
`AXES_SENSITIVE_PARAMETERS` doesn't affect database handler logs
Hello!
I encountered an issue when attempting to utilize the `AXES_SENSITIVE_PARAMETERS` configuration in order to prevent usernames from being written into our log files, even though I added the setting like so:
```python
AXES_SENSITIVE_PARAMETERS = ["username"]
```
Whenever a login attempt fails a log is still being written:
![image](https://user-images.githubusercontent.com/107052238/221629353-c4cf3263-4e21-4565-941d-f0846bc9843e.png)

I might've misunderstood how it works, but I did some debugging and found the following:
1. Inside `axes.handlers.database.py` some of the WARN logs are being written using the `client_str` variable
2. The `client_str` variable is produced from the `get_client_str` function in `axes.helpers.py`
3. In `get_client_str`, lines 298-302 should be replaced with a call to `get_query_str`, which does the same thing but also "cleanses" the dictionary, using the `AXES_SENSITIVE_PARAMETERS ` configuration value.

I'd love some feedback whether I misunderstood the usage of this configuration, or is this an actual issue,
Thanks! Shai.


Discussion:
Hey, sounds reasonable. Would you like to open a PR with the proposed changes so that we can review the implementation and upstream it?

Resolving patch:
diff --git a/axes/helpers.py b/axes/helpers.py
--- a/axes/helpers.py
+++ b/axes/helpers.py
@@ -306,7 +306,7 @@ def get_client_str(
         client_dict = {}
         for client in client_list:
             client_dict.update(client)
-
+    client_dict = cleanse_parameters(client_dict.copy())
     # Path info is always included as last component in the client string for traceability purposes
     if path_info and isinstance(path_info, (tuple, list)):
         path_info = path_info[0]


Test patch:
diff --git a/tests/test_helpers.py b/tests/test_helpers.py
--- a/tests/test_helpers.py
+++ b/tests/test_helpers.py
@@ -269,6 +269,26 @@ def test_get_client_str_callable_using_request(self):
             self.email,
         )
 
+    @override_settings(AXES_SENSITIVE_PARAMETERS=["username"])
+    def test_get_client_str_with_sensitive_parameters(self):
+        username = "test@example.com"
+        ip_address = "127.0.0.1"
+        user_agent = "Googlebot/2.1 (+http://www.googlebot.com/bot.html)"
+        path_info = "/admin/"
+
+        expected = self.get_expected_client_str(
+            "********************",
+            ip_address,
+            user_agent,
+            path_info,
+            self.request
+        )
+        actual = get_client_str(
+            username, ip_address, user_agent, path_info, self.request
+        )
+
+        self.assertEqual(expected, actual)
+
 
 def get_dummy_client_str(username, ip_address, user_agent, path_info, request):
     return "client string"