Browse Source

LDAP backend for VPN

Baptiste Jonglez 11 years ago
parent
commit
e9cfdc2cc6
2 changed files with 55 additions and 1 deletions
  1. 3 0
      coin/resources/models.py
  2. 52 1
      coin/vpn/models.py

+ 3 - 0
coin/resources/models.py

@@ -45,6 +45,9 @@ class IPPool(models.Model):
 
 
 class IPSubnet(models.Model):
+    # TODO: find some way to signal to Subscriptions objects when a subnet
+    # gets modified (so that the subscription can update the LDAP backend
+    # accordingly)
     inet = CidrAddressField(blank=True, validators=[validate_subnet],
                             verbose_name="Leave empty for automatic allocation")
     objects = NetManager()

+ 52 - 1
coin/vpn/models.py

@@ -1,7 +1,12 @@
+# -*- coding: utf-8 -*-
 from django.db import models
 from django.core.exceptions import ValidationError
 from netfields import InetAddressField, NetManager
 from netaddr import IPAddress
+import ldapdb.models
+from ldapdb.models.fields import CharField, IntegerField, ListField
+
+from coin.models import CoinLdapSyncModel
 
 
 def validate_v4(address):
@@ -13,8 +18,9 @@ def validate_v6(address):
         raise ValidationError('{} is not an IPv6 address'.format(address))
 
 
-class VPNSubscription(models.Model):
+class VPNSubscription(CoinLdapSyncModel):
     administrative_subscription = models.OneToOneField('offers.OfferSubscription')
+    # TODO: do some access control to prevent the user from changing this field
     activated = models.BooleanField(default=False)
     login = models.CharField(max_length=50)
     # TODO: define which hash to use
@@ -24,6 +30,29 @@ class VPNSubscription(models.Model):
 
     objects = NetManager()
 
+    def get_subnets(version):
+        subnets = self.administrative_subscription.ip_subnet.all()
+        return [subnet for subnet in subnets if subnet.inet.version == version]
+
+    def sync_to_ldap(self, creation):
+        if creation:
+            config = LdapVPNConfig()
+        else:
+            config = LdapVPNConfig.objects.get(pk=self.login)
+        config.login = config.sn = self.login
+        # TODO: salt + hash the password
+        config.password = self.password
+        config.active = 'yes' if self.activated else 'no'
+        config.ipv4_endpoint = str(self.ipv4_endpoint)
+        config.ipv6_endpoint = str(self.ipv6_endpoint)
+        config.ranges_v4 = [str(s) for s in self.get_subnets(4)]
+        config.ranges_v4 = [str(s) for s in self.get_subnets(6)]
+        config.save()
+
+    def delete_from_ldap(self):
+        # TODO: simple delete?
+        pass
+
     def clean(self):
         # TODO: this should be factored for other technologies (DSL, etc)
         subnets = self.administrative_subscription.ip_subnet.all()
@@ -53,3 +82,25 @@ class VPNSubscription(models.Model):
 
     def __unicode__(self):
         return self.login
+
+
+class LdapVPNConfig(ldapdb.models.Model):
+    # TODO: déplacer ligne suivante dans settings.py
+    base_dn = "ou=vpn,ou=unix,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
+    object_classes = ['person', 'organizationalPerson', 'inetOrgPerson',
+                      'top', 'radiusprofile']
+
+    login = CharField(db_column='cn', primary_key=True, max_length=255)
+    sn = CharField(db_column='sn', primary_key=True, max_length=255)
+    password = CharField(db_column='userPassword', max_length=255)
+    active = CharField(db_column='dialupAccess', max_length=3)
+    ipv4_endpoint = CharField(db_column='radiusFramedIPAddress', max_length=16)
+    ipv6_endpoint = CharField(db_column='postalAddress', max_length=40)
+    ranges_v4 = ListField(db_column='radiusFramedRoute')
+    ranges_v6 = ListField(db_column='registeredAddress')
+
+    def __unicode__(self):
+        return self.login
+
+    class Meta:
+        managed = False  # Indique à South de ne pas gérer le model LdapUser