Browse Source

login automatique basé sur l’IP

Élie Bouttier 7 years ago
parent
commit
1fde70e2d5
3 changed files with 102 additions and 0 deletions
  1. 1 0
      accounts/urls.py
  2. 37 0
      accounts/views.py
  3. 64 0
      services/utils/ip_conversion.py

+ 1 - 0
accounts/urls.py

@@ -10,5 +10,6 @@ urlpatterns = [
     url(r'^profile/$', views.profile, name='profile'),
     url(r'^auth_api/(?P<token>[a-zA-Z0-9]{32})/$', views.auth_api, name='auth_api'),
     url(r'^password_reset/$', auth_views.PasswordResetView.as_view(form_class=PasswordResetForm), name='password_reset'),
+    url(r'^login/$', views.login, name='login'),
     url(r'^', include('django.contrib.auth.urls')),
 ]

+ 37 - 0
accounts/views.py

@@ -7,9 +7,46 @@ from django.http import HttpResponse, HttpResponseBadRequest
 from django.views.decorators.http import require_POST
 from django.views.decorators.csrf import csrf_exempt
 from django.contrib.auth import authenticate, get_user_model
+from django.contrib.auth.views import LoginView
+from django.contrib.auth import login as auth_login
 
+from services.models import IPResource
+from djadhere.utils import get_active_filter
 from .forms import UserForm, ProfileForm
 
+from ipaddress import ip_address, IPv6Address
+from services.utils.ip_conversion import ipv6_to_ipv4
+
+
+def login(request):
+    def try_authenticate_from_ip():
+        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+        if x_forwarded_for:
+            ip = x_forwarded_for.split(',')[0]
+        else:
+            ip = request.META.get('REMOTE_ADDR')
+        try:
+            ip = ip_address(ip)
+        except ValueError:
+            return
+        try:
+            if type(ip) == IPv6Address:
+                ip = ipv6_to_ipv4(ip)
+            ip = IPResource.objects.get(ip=ip.exploded)
+        except (IPResource.DoesNotExist, ValueError):
+            return
+        allocation = ip.allocations.filter(get_active_filter()).first()
+        if not allocation:
+            return
+        user = allocation.service.adhesion.user
+        if not user: # corporation
+            return
+        if user.is_superuser: # superusers must enter password
+            return
+        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
+    try_authenticate_from_ip()
+    return LoginView.as_view(redirect_authenticated_user=True)(request)
+
 
 @login_required
 def profile(request):

+ 64 - 0
services/utils/ip_conversion.py

@@ -0,0 +1,64 @@
+from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network
+
+
+IPV4_NETWORKS = [
+    IPv4Network('91.224.148.0/24'),
+    IPv4Network('91.224.149.0/24'),
+    IPv4Network('89.234.156.0/24'),
+    IPv4Network('89.234.157.0/24'),
+    IPv4Network('185.119.168.0/24'),
+    IPv4Network('185.119.169.0/24'),
+    IPv4Network('185.119.170.0/24'),
+    IPv4Network('185.119.171.0/24'),
+]
+
+IPV6_NETWORKS = [
+    IPv6Network('2a03:7220:8080::/48'),
+    IPv6Network('2a03:7220:8081::/48'),
+    IPv6Network('2a03:7220:8083::/48'),
+    IPv6Network('2a03:7220:8084::/48'),
+    IPv6Network('2a03:7220:8085::/48'),
+    IPv6Network('2a03:7220:8086::/48'),
+    IPv6Network('2a03:7220:8087::/48'),
+    IPv6Network('2a03:7220:8088::/48'),
+]
+
+
+def ipv4_to_ipv6(ipv4):
+    ipv4_network = IPv4Network((ipv4, 24), strict=False)
+    ipv6_network = IPV6_NETWORKS[IPV4_NETWORKS.index(ipv4_network)]
+    return list(ipv6_network.subnets(8))[ipv4.packed[3]]
+
+
+def ipv6_to_ipv4(ipv6):
+    ipv6_network = IPv6Network((ipv6, 48), strict=False)
+    ipv4_network = IPV4_NETWORKS[IPV6_NETWORKS.index(ipv6_network)]
+    return ipv4_network[ipv6.packed[6]]
+
+
+if __name__ == '__main__':
+    ipv4_to_ipv6_tests = {
+        IPv4Address('91.224.148.0'): IPv6Network('2a03:7220:8080::/56'),
+        IPv4Address('91.224.149.170'): IPv6Network('2a03:7220:8081:aa00::/56'),
+        IPv4Address('89.234.156.195'): IPv6Network('2a03:7220:8083:c300::/56'),
+        IPv4Address('89.234.157.255'): IPv6Network('2a03:7220:8084:ff00::/56'),
+    }
+    for ipv4, ipv6 in ipv4_to_ipv6_tests.items():
+        if ipv4_to_ipv6(ipv4) != ipv6:
+            raise AssertionError('ipv4_to_ipv6(%s) = %s ≠ %s' \
+                        % (ipv4, ipv4_to_ipv6(ipv4), ipv6))
+
+    ipv6_to_ipv4_tests = {
+        IPv6Address('2a03:7220:8080:ff0d:35ac:3820::23'): IPv4Address('91.224.148.255'),
+        IPv6Address('2a03:7220:8081:aa0d:35ac:3820::23'): IPv4Address('91.224.149.170'),
+        IPv6Address('2a03:7220:8083:000d:35ac:3820::0'): IPv4Address('89.234.156.0'),
+        IPv6Address('2a03:7220:8084:220d:35ac:3820::1'): IPv4Address('89.234.157.34'),
+        IPv6Address('2a03:7220:8085:800d:35ac:3820::ff'): IPv4Address('185.119.168.128'),
+        IPv6Address('2a03:7220:8086:2a0d:35ac:3820::f'): IPv4Address('185.119.169.42'),
+        IPv6Address('2a03:7220:8087:f00d:35ac:3820::a'): IPv4Address('185.119.170.240'),
+        IPv6Address('2a03:7220:8088:f59d:35ac:abcd:dead:beaf'): IPv4Address('185.119.171.245'),
+    }
+    for ipv6, ipv4 in ipv6_to_ipv4_tests.items():
+        if ipv6_to_ipv4(ipv6) != ipv4:
+            raise AssertionError('iv6_to_ipv4(%s) = %s ≠ %s' \
+                        % (ipv6, ipv6_to_ipv4(ipv6), ipv4))