models.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # -*- coding: utf-8 -*-
  2. from django.db import models
  3. from django.core.exceptions import ValidationError
  4. from netfields import InetAddressField, NetManager
  5. import ldapdb.models
  6. from ldapdb.models.fields import CharField, ListField
  7. from coin.mixins import CoinLdapSyncMixin
  8. from coin.offers.models import OfferSubscription
  9. from coin.offers.backends import ValidateBackendType
  10. from coin import utils
  11. from coin import validation
  12. class VPNSubscription(CoinLdapSyncMixin, models.Model):
  13. url_namespace = "vpn"
  14. backend_name = "openvpn_ldap"
  15. administrative_subscription = models.OneToOneField(
  16. 'offers.OfferSubscription',
  17. related_name=backend_name,
  18. validators=[ValidateBackendType(backend_name)])
  19. activated = models.BooleanField(default=False)
  20. login = models.CharField(max_length=50, unique=True)
  21. password = models.CharField(max_length=256)
  22. ipv4_endpoint = InetAddressField(validators=[validation.validate_v4],
  23. blank=True, null=True)
  24. ipv6_endpoint = InetAddressField(validators=[validation.validate_v6],
  25. blank=True, null=True)
  26. comment = models.CharField(blank=True, max_length=512)
  27. objects = NetManager()
  28. # These two methods are part of the general configuration interface.
  29. def save_subnet(self, subnet, creation):
  30. self.check_endpoints(delete=True)
  31. # We potentially changed the endpoints, so we need to save.
  32. self.full_clean()
  33. self.save()
  34. def delete_subnet(self, subnet):
  35. self.save_subnet(subnet, False)
  36. def get_subnets(self, version):
  37. subnets = self.administrative_subscription.ip_subnet.all()
  38. return [subnet for subnet in subnets if subnet.inet.version == version]
  39. def sync_to_ldap(self, creation):
  40. if creation:
  41. config = LdapVPNConfig()
  42. else:
  43. config = LdapVPNConfig.objects.get(pk=self.login)
  44. config.login = config.sn = self.login
  45. config.password = self.password
  46. config.active = 'yes' if self.activated else 'no'
  47. config.ipv4_endpoint = utils.str_or_none(self.ipv4_endpoint)
  48. config.ipv6_endpoint = utils.str_or_none(self.ipv6_endpoint)
  49. config.ranges_v4 = [str(s) for s in self.get_subnets(4)]
  50. config.ranges_v6 = [str(s) for s in self.get_subnets(6)]
  51. config.save()
  52. def delete_from_ldap(self):
  53. LdapVPNConfig.objects.get(pk=self.login).delete()
  54. def generate_endpoints(self, v4=True, v6=True):
  55. """Generate IP endpoints in one of the attributed IP subnets. If there is
  56. no available subnet for a given address family, then no endpoint
  57. is generated for this address family. If there already is an
  58. endpoint, do nothing.
  59. Returns True if an endpoint was generated.
  60. TODO: this should be factored for other technologies (DSL, etc)
  61. """
  62. subnets = self.administrative_subscription.ip_subnet.all()
  63. updated = False
  64. if v4 and self.ipv4_endpoint is None:
  65. subnets_v4 = [s for s in subnets if s.inet.version == 4]
  66. if len(subnets_v4) > 0:
  67. self.ipv4_endpoint = subnets_v4[0].inet.ip
  68. updated = True
  69. if v6 and self.ipv6_endpoint is None:
  70. subnets_v6 = [s for s in subnets if s.inet.version == 6]
  71. if len(subnets_v6) > 0:
  72. # With v6, we choose the second host of the subnet (cafe::1)
  73. gen = subnets_v6[0].inet.iter_hosts()
  74. gen.next()
  75. self.ipv6_endpoint = gen.next()
  76. updated = True
  77. return updated
  78. def check_endpoints(self, delete=False):
  79. """Check that the IP endpoints are included in one of the attributed IP
  80. subnets.
  81. If [delete] is True, then simply delete the faulty endpoints
  82. instead of raising an exception.
  83. """
  84. subnets = self.administrative_subscription.ip_subnet.all()
  85. is_faulty = lambda endpoint : endpoint and not any([endpoint in subnet.inet for subnet in subnets])
  86. if is_faulty(self.ipv4_endpoint):
  87. if delete:
  88. self.ipv4_endpoint = None
  89. else:
  90. raise ValidationError("Endpoint {} is not in an attributed range".format(self.ipv4_endpoint))
  91. if is_faulty(self.ipv6_endpoint):
  92. if delete:
  93. self.ipv6_endpoint = None
  94. else:
  95. raise ValidationError("Endpoint {} is not in an attributed range".format(self.ipv6_endpoint))
  96. def clean(self):
  97. # Hash password if needed
  98. self.password = utils.ldap_hash(self.password)
  99. # If saving for the first time and IP endpoints are not specified,
  100. # generate them automatically.
  101. if self.pk is None:
  102. self.generate_endpoints()
  103. self.check_endpoints()
  104. def __unicode__(self):
  105. return 'VPN ' + self.login
  106. class LdapVPNConfig(ldapdb.models.Model):
  107. # TODO: déplacer ligne suivante dans settings.py
  108. base_dn = "ou=vpn,o=ILLYSE,l=Villeurbanne,st=RHA,c=FR"
  109. object_classes = ['person', 'organizationalPerson', 'inetOrgPerson',
  110. 'top', 'radiusprofile']
  111. login = CharField(db_column='cn', primary_key=True, max_length=255)
  112. sn = CharField(db_column='sn', max_length=255)
  113. password = CharField(db_column='userPassword', max_length=255)
  114. active = CharField(db_column='dialupAccess', max_length=3)
  115. ipv4_endpoint = CharField(db_column='radiusFramedIPAddress', max_length=16)
  116. ipv6_endpoint = CharField(db_column='postalAddress', max_length=40)
  117. ranges_v4 = ListField(db_column='radiusFramedRoute')
  118. ranges_v6 = ListField(db_column='registeredAddress')
  119. def __unicode__(self):
  120. return self.login
  121. class Meta:
  122. managed = False # Indique à South de ne pas gérer le model LdapUser