jazzband / django-axes

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Possibility to override get_client_ip method

PaulM5406 opened this issue · comments

Hi,

First of all, thank you for this package and your work !

My problem is that I cannot find a proper configuration for django_ipware that fits my case.

My server is behind a load balancer and a reverse proxy.
The load balancer is configured in append mode and so appends the client ip address to the X-Forwarded-For header existing values or create the header with the client ip address if it does not exist in the request.
The reverse proxy does nothing in particular with this header, just passes it to the server.

So, I get something like this on the server: X-Forwarded-For = <original_data_from_client> -- ... -- <client_ip_set_by_load_balancer>.

I configure django-axes with AXES_PROXY_ORDER = 'right-most' as I want django-axes to get the last ip address contained in the header, even if other values are invalid.

django_ipware does not enable that. It skips the whole header if the first or the last ip address is not a valid one.
https://github.com/un33k/django-ipware/blob/master/ipware/ip.py#L27
https://github.com/un33k/django-ipware/blob/930f3293eb11b2bfc221959434e8501c165a2b61/ipware/utils.py#L94

If I try to spoof my ip address using a valid ip address, all works good, django_axes gets the most-right ones but if I set an invalid ip address in the header, the whole header is skipped.

I don't know what would be the best way to fix that, if I should open an issue in django_ipware or update django-axes to add the possibility to define a custom and simple get_client_ip method in this case ?

Thank you !

Hey @PaulM5406!

Sure, it should be easy to implement a customization that enables overriding the get_client_ip implementation by supplying a different callable or a path to calling a different function, for example, similarly to AXES_USERNAME_CALLABLE etc:

https://django-axes.readthedocs.io/en/latest/4_configuration.html#configuring-project-settings

The current implementation for fetching the IP is:

https://github.com/jazzband/django-axes/blob/master/axes/helpers.py#L151

The same helpers.py module has different examples of using a callable for fetching different parameters as well.

Would you be interested in opening a PR for this? The feature should include at least the implementation and unit tests for it, and preferably documentation as well.

Hey @aleksihakli, i just opened a PR for this)

Hey @aleksihakli , @hirotasoshu,

Thank you for your quick response and implementation ! I couldn't believe it this has been done when I woke up this morning^^

When do you expect a new pypi release of django-axes ?

Now that it is possible to implement a custom get_client_ip, it would be nice to make the django_ipware an optional dependency. Unfortunately, I think it is not possible to specify an optional dependency that would be installed by default without adding a custom post-install script to the setup.py.

Hey @PaulM5406! This has been released as 5.41.0 on 2023-04-02.

If you figure out a good way for making the deps optional do let us know :)

Hey @aleksihakli ! Thank you, I am using this new feature and all works great !

In regards to making the deps optional, there is only one correct way to do that. It would be to exclude django-ipware from the list of the default requirements and add it as a extra_requires. People could still install it using django-axes[ipware] for example. As it would be a breaking change, may it be considered for next major version ?

Well, that would be a good way to implement the optional deps, assuming there would be a good baseline implementation for fetching the client IP address in this package.

The reason django-ipware was adopted as a baseline IP calculation solution is that it abstracts the IP management and lets a specialized package handle that part of the HTTP requests. If you think there's a good alternative solution we could use as a stock implementation I'd personally be open to improvements on that part.

There's a bunch of other "small" breaking changes that would be a good fit for a version 6.x release. I'm all for opening up e.g. a new branch for that development or alternatively freezing 5.x into a maintenance release and branch :)

See the proposed 6.x changes in:

https://github.com/jazzband/django-axes/issues?q=is%3Aissue+is%3Aopen+label%3A6.x