models.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. # -*- coding: utf-8 -*-
  2. from django.db import models
  3. from django.core.exceptions import ValidationError
  4. from netfields import InetAddressField, NetManager
  5. from netaddr import IPAddress
  6. import ldapdb.models
  7. from ldapdb.models.fields import CharField, IntegerField, ListField
  8. from coin.models import CoinLdapSyncModel
  9. def validate_v4(address):
  10. if address.version != 4:
  11. raise ValidationError('{} is not an IPv4 address'.format(address))
  12. def validate_v6(address):
  13. if address.version != 6:
  14. raise ValidationError('{} is not an IPv6 address'.format(address))
  15. class VPNSubscription(CoinLdapSyncModel):
  16. administrative_subscription = models.OneToOneField('offers.OfferSubscription')
  17. # TODO: do some access control to prevent the user from changing this field
  18. activated = models.BooleanField(default=False)
  19. login = models.CharField(max_length=50)
  20. # TODO: define which hash to use
  21. password = models.CharField(max_length=256)
  22. ipv4_endpoint = InetAddressField(validators=[validate_v4], blank=True)
  23. ipv6_endpoint = InetAddressField(validators=[validate_v6], blank=True)
  24. objects = NetManager()
  25. def get_subnets(self, version):
  26. subnets = self.administrative_subscription.ip_subnet.all()
  27. return [subnet for subnet in subnets if subnet.inet.version == version]
  28. def sync_to_ldap(self, creation):
  29. if creation:
  30. config = LdapVPNConfig()
  31. else:
  32. config = LdapVPNConfig.objects.get(pk=self.login)
  33. config.login = config.sn = self.login
  34. # TODO: salt + hash the password
  35. config.password = self.password
  36. config.active = 'yes' if self.activated else 'no'
  37. config.ipv4_endpoint = str(self.ipv4_endpoint)
  38. config.ipv6_endpoint = str(self.ipv6_endpoint)
  39. config.ranges_v4 = [str(s) for s in self.get_subnets(4)]
  40. config.ranges_v6 = [str(s) for s in self.get_subnets(6)]
  41. config.save()
  42. def delete_from_ldap(self):
  43. # TODO: simple delete?
  44. pass
  45. def clean(self):
  46. # TODO: this should be factored for other technologies (DSL, etc)
  47. subnets = self.administrative_subscription.ip_subnet.all()
  48. # If saving for the first time and IP endpoints are not specified,
  49. # generate them automatically.
  50. if self.pk is None:
  51. subnets_v4 = [s for s in subnets if s.inet.version == 4]
  52. subnets_v6 = [s for s in subnets if s.inet.version == 6]
  53. if self.ipv4_endpoint is None:
  54. if len(subnets_v4) == 0:
  55. # TODO: should we fail silently instead?
  56. raise ValidationError('No IPv4 subnet defined, needed to choose an endpoint from')
  57. self.ipv4_endpoint = subnets_v4[0].inet.ip
  58. if self.ipv6_endpoint is None:
  59. if len(subnets_v6) == 0:
  60. # TODO: should we fail silently instead?
  61. raise ValidationError('No IPv6 subnet defined, needed to choose an endpoint from')
  62. # With v6, we choose the second host of the subnet (cafe::1)
  63. gen = subnets_v6[0].inet.iter_hosts()
  64. gen.next()
  65. self.ipv6_endpoint = gen.next()
  66. # Check that the endpoints are included in one of the routed subnets
  67. for endpoint in [self.ipv4_endpoint, self.ipv6_endpoint]:
  68. if endpoint:
  69. if not any([endpoint in subnet.inet for subnet in subnets]):
  70. raise ValidationError("Endpoint {} is not in an attributed range".format(endpoint))
  71. def __unicode__(self):
  72. return self.login
  73. class LdapVPNConfig(ldapdb.models.Model):
  74. # TODO: déplacer ligne suivante dans settings.py
  75. base_dn = "ou=vpn,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
  76. object_classes = ['person', 'organizationalPerson', 'inetOrgPerson',
  77. 'top', 'radiusprofile']
  78. login = CharField(db_column='cn', primary_key=True, max_length=255)
  79. sn = CharField(db_column='sn', max_length=255)
  80. password = CharField(db_column='userPassword', max_length=255)
  81. active = CharField(db_column='dialupAccess', max_length=3)
  82. ipv4_endpoint = CharField(db_column='radiusFramedIPAddress', max_length=16)
  83. ipv6_endpoint = CharField(db_column='postalAddress', max_length=40)
  84. ranges_v4 = ListField(db_column='radiusFramedRoute')
  85. ranges_v6 = ListField(db_column='registeredAddress')
  86. def __unicode__(self):
  87. return self.login
  88. class Meta:
  89. managed = False # Indique à South de ne pas gérer le model LdapUser