changeset 3212:6c28533d122c beta

IP restrictions now also enabled for IPv6
author Marcin Kuzminski <marcin@python-works.com>
date Wed, 23 Jan 2013 23:51:57 +0100
parents c77a846a24d5
children f5dcee2b3153
files rhodecode/lib/auth.py rhodecode/model/db.py rhodecode/model/validators.py
diffstat 3 files changed, 37 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/rhodecode/lib/auth.py	Wed Jan 23 22:48:04 2013 +0100
+++ b/rhodecode/lib/auth.py	Wed Jan 23 23:51:57 2013 +0100
@@ -34,6 +34,7 @@
 from pylons import config, url, request
 from pylons.controllers.util import abort, redirect
 from pylons.i18n.translation import _
+from sqlalchemy.orm.exc import ObjectDeletedError
 
 from rhodecode import __platform__, is_windows, is_unix
 from rhodecode.model.meta import Session
@@ -447,8 +448,13 @@
             user_ips = user_ips.options(FromCache("sql_cache_short",
                                                   "get_user_ips_%s" % user_id))
         for ip in user_ips:
-            _set.add(ip.ip_addr)
-        return _set or set(['0.0.0.0/0'])
+            try:
+                _set.add(ip.ip_addr)
+            except ObjectDeletedError:
+                # since we use heavy caching sometimes it happens that we get
+                # deleted objects here, we just skip them
+                pass
+        return _set or set(['0.0.0.0/0', '::/0'])
 
 
 def set_available_permissions(config):
@@ -990,6 +996,13 @@
     log.debug('checking if ip:%s is subnet of %s' % (source_ip, allowed_ips))
     if isinstance(allowed_ips, (tuple, list, set)):
         for ip in allowed_ips:
-            if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip):
-                return True
+            try:
+                if ipaddr.IPAddress(source_ip) in ipaddr.IPNetwork(ip):
+                    return True
+                # for any case we cannot determine the IP, don't crash just
+                # skip it and log as error, we want to say forbidden still when
+                # sending bad IP
+            except Exception:
+                log.error(traceback.format_exc())
+                continue
     return False
--- a/rhodecode/model/db.py	Wed Jan 23 22:48:04 2013 +0100
+++ b/rhodecode/model/db.py	Wed Jan 23 23:51:57 2013 +0100
@@ -562,7 +562,7 @@
     @classmethod
     def _get_ip_range(cls, ip_addr):
         from rhodecode.lib import ipaddr
-        net = ipaddr.IPv4Network(ip_addr)
+        net = ipaddr.IPNetwork(address=ip_addr)
         return [str(net.network), str(net.broadcast)]
 
     def __json__(self):
--- a/rhodecode/model/validators.py	Wed Jan 23 22:48:04 2013 +0100
+++ b/rhodecode/model/validators.py	Wed Jan 23 23:51:57 2013 +0100
@@ -14,6 +14,7 @@
     NotEmpty, IPAddress, CIDR
 )
 from rhodecode.lib.compat import OrderedSet
+from rhodecode.lib import ipaddr
 from rhodecode.lib.utils import repo_name_slug
 from rhodecode.model.db import RepoGroup, Repository, UsersGroup, User,\
     ChangesetStatus
@@ -711,35 +712,31 @@
 def ValidIp():
     class _validator(CIDR):
         messages = dict(
-            badFormat=_('Please enter a valid IP address (a.b.c.d)'),
-            illegalOctets=_('The octets must be within the range of 0-255'
-                ' (not %(octet)r)'),
+            badFormat=_('Please enter a valid IPv4 or IpV6 address'),
             illegalBits=_('The network size (bits) must be within the range'
                 ' of 0-32 (not %(bits)r)'))
 
+        def to_python(self, value, state):
+            v = super(_validator, self).to_python(value, state)
+            v = v.strip()
+            net = ipaddr.IPNetwork(address=v)
+            if isinstance(net, ipaddr.IPv4Network):
+                #if IPv4 doesn't end with a mask, add /32
+                if '/' not in value:
+                    v += '/32'
+            if isinstance(net, ipaddr.IPv6Network):
+                #if IPv6 doesn't end with a mask, add /128
+                if '/' not in value:
+                    v += '/128'
+            return v
+
         def validate_python(self, value, state):
             try:
-                # Split into octets and bits
-                if '/' in value:  # a.b.c.d/e
-                    addr, bits = value.split('/')
-                else:  # a.b.c.d
-                    addr, bits = value, 32
-                # Use IPAddress validator to validate the IP part
-                IPAddress.validate_python(self, addr, state)
-                # Bits (netmask) correct?
-                if not 0 <= int(bits) <= 32:
-                    raise formencode.Invalid(
-                        self.message('illegalBits', state, bits=bits),
-                        value, state)
-            # Splitting faild: wrong syntax
+                addr = value.strip()
+                #this raises an ValueError if address is not IpV4 or IpV6
+                ipaddr.IPNetwork(address=addr)
             except ValueError:
                 raise formencode.Invalid(self.message('badFormat', state),
                                          value, state)
 
-        def to_python(self, value, state):
-            v = super(_validator, self).to_python(value, state)
-            #if IP doesn't end with a mask, add /32
-            if '/' not in value:
-                v += '/32'
-            return v
     return _validator